Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将Decorator模式与C#MEF相结合?_C#_Design Patterns_Mef_Decorator - Fatal编程技术网

如何将Decorator模式与C#MEF相结合?

如何将Decorator模式与C#MEF相结合?,c#,design-patterns,mef,decorator,C#,Design Patterns,Mef,Decorator,我正在尝试增强当前使用C#MEF的已建立程序集。由于这些程序集已经在生产中使用,因此直接修改单个类目前不是一种可行的方法。我主要是在现有行为的基础上添加新行为。例如,我有: public IExtension { Object Execute(); } public BaseExtension : IExtension { // other methods and members public virtual Object Execute() {

我正在尝试增强当前使用C#MEF的已建立程序集。由于这些程序集已经在生产中使用,因此直接修改单个类目前不是一种可行的方法。我主要是在现有行为的基础上添加新行为。例如,我有:

public IExtension
{
     Object Execute(); 
}


public BaseExtension : IExtension
{
     // other methods and members

     public virtual Object Execute()
     {
         // do operations here. 
     }
}

[Export(typeof(IExtension)]
public AppRecordExtension : BaseExtension
{
     // .. other methods and members
     public override Object Execute()
     {
         base.Execute(); // shown just for example..
         this.someOperation(); 
     }
}

// other extensions made.
现在,当MEF容器在驱动程序的方法中调用扩展时,上述方法起作用:

[ImportMany(typeof(IExtension)]
private IEnumerable<Lazy<IExtension>> operations;

public void ExecuteExtensions() 
{
     var catalog = new AggregateCatalog( new AssemblyCatalog(Assembly.GetExecutingAssembly()), new DirectoryCatalog("extensions", ".dll")); 
     CompositionContainer container = new CompositionContainer(catalog); 
     container.ComposeParts(this); 

     Dictionary<IExtension, object> result = new Dictionary<IExtension, object>(); 

     foreach(Lazy(IExtension> extension in operations) 
     {
         result.Add((extension.Value, extension.Value.Execute()); 

     }
}
有人能帮忙吗?我希望确保当容器拾取扩展时,也会拾取新的行为,具体取决于传递的参数(例如,如果isBatchable=true,则添加BatchableExtension,等等)。如果是非MEF,则上面的内容类似于:

 public void Main(String[] args) 
 {
     IExtension ext = new AppRecordExtension(); 
     // this is the part where I want to simulate when I use MEF. 
     IExtension ext2 = new MonitoringExtension(new BatchableExtension(ext)); 
     ext2.Execute(); 
 }

MEF不支持这种功能,所以您必须自己做。您可以使用-公开用于构建装饰对象的数据,然后将扩展导出如下所示:

[ExtensionExport(IsBatch = true, IsMonitoring = false)]
public AppRecordExtension : BaseExtension
{
     // ...
}
在导入扩展的类中:

[ImportMany]
private IEnumerable<Lazy<IExtension, IExtensionMetadata>> operations;

public void ExecuteExtensions()
{
    // ...

    foreach(Lazy(IExtension, IExtensionMetadata> extension in operations) 
    {
        IExtension decoratedExtension = DecorateExtension(extension);
        result.Add(decoratedExtension, decoratedExtension.Execute()); 
    }
}

private IExtension DecorateExtension(Lazy<IExtension, IExtensionMetadata> exportedExtension)
{
    IExtension ext = exportedExtension.Value;
    if (exportedExtension.Metadata.IsBatch)
    {
        ext = new BatchableExtension(ext);
    }
    if (exportedExtension.Metadata.IsMonitoring)
    {
        ext = new MonitoringExtension(ext);
    }

    // Other decorating logic...

    return ext;
}
[ImportMany]
私人可数业务;
public void ExecuteExtensions()
{
// ...
foreach(惰性(IExtension,IExtensionMetadata>operations中的扩展)
{
IExtension DecorateExtension=DecorateExtension(扩展名);
Add(decoratedExtension,decoratedExtension.Execute());
}
}
私有IExtension装饰扩展(惰性导出扩展)
{
IExtension ext=exportedExtension.Value;
if(exportedExtension.Metadata.IsBatch)
{
ext=新的BatchableExtension(ext);
}
if(exportedExtension.Metadata.IsMonitoring)
{
ext=新的监视扩展(ext);
}
//其他装饰逻辑。。。
返回ext;
}

您可以轻松添加基本支持。您只需要一个自定义目录,以您希望的方式重写合同:

public class DecoratorChainCatalog : ComposablePartCatalog
{
    private List<Type> myDecoratorChain;
    private List<ComposablePartDefinition> myParts;

    private string myContractName;

    public DecoratorChainCatalog( Type contract )
        : this( AttributedModelServices.GetContractName( contract ) )
    {
    }

    public DecoratorChainCatalog( string contract )
    {
        Contract.RequiresNotNullNotEmpty( contract, "contract" );

        myContractName = contract;

        myDecoratorChain = new List<Type>();
        myParts = new List<ComposablePartDefinition>();
    }

    public void Add( Type type )
    {
        Contract.Invariant( !myParts.Any(), "Recomposition not supported" );

        myDecoratorChain.Add( type );
    }

    public override IQueryable<ComposablePartDefinition> Parts
    {
        get
        {
            ComposeDecoration();
            return myParts.AsQueryable();
        }
    }

    [SecuritySafeCritical]
    private void ComposeDecoration()
    {
        if ( myParts.Any() )
        {
            return;
        }

        Trace.WriteLine( "!! ComposeDecoration !!" );

        var contracts = new List<string>();
        foreach ( var type in myDecoratorChain )
        {
            var originalPart = AttributedModelServices.CreatePartDefinition( type, null );

            var importDefs = originalPart.ImportDefinitions.ToList();

            if ( type != myDecoratorChain.First() )
            {
                RewriteContract( importDefs, contracts.Last() );
            }

            var exportDefs = originalPart.ExportDefinitions.ToList();

            if ( type != myDecoratorChain.Last() )
            {
                contracts.Add( Guid.NewGuid().ToString() );
                RewriteContract( exportDefs, type, contracts.Last() );
            }

            // as we pass it to lazy below we have to copy it to local variable - otherwise we create a closure with the loop iterator variable
            // and this will cause the actual part type to be changed
            var partType = type;
            var part = ReflectionModelServices.CreatePartDefinition(
                new Lazy<Type>( () => partType ),
                ReflectionModelServices.IsDisposalRequired( originalPart ),
                new Lazy<IEnumerable<ImportDefinition>>( () => importDefs ),
                new Lazy<IEnumerable<ExportDefinition>>( () => exportDefs ),
                new Lazy<IDictionary<string, object>>( () => new Dictionary<string, object>() ),
                null );

            myParts.Add( part );
        }

        // no add possible any longer
        myDecoratorChain = null;
    }

    [SecuritySafeCritical]
    private void RewriteContract( IList<ImportDefinition> importDefs, string newContract )
    {
        var importToDecorate = importDefs.Single( d => d.ContractName == myContractName );
        importDefs.Remove( importToDecorate );

        Contract.Invariant( importToDecorate.Cardinality == ImportCardinality.ExactlyOne, "Decoration of Cardinality " + importToDecorate.Cardinality + " not supported" );
        Contract.Invariant( ReflectionModelServices.IsImportingParameter( importToDecorate ), "Decoration of property injection not supported" );

        var param = ReflectionModelServices.GetImportingParameter( importToDecorate );
        var importDef = ReflectionModelServices.CreateImportDefinition(
            param,
            newContract,
            AttributedModelServices.GetTypeIdentity( param.Value.ParameterType ),
            Enumerable.Empty<KeyValuePair<string, Type>>(),
            importToDecorate.Cardinality,
            CreationPolicy.Any,
            null );

        importDefs.Add( importDef );
    }

    [SecuritySafeCritical]
    private void RewriteContract( IList<ExportDefinition> exportDefs, Type exportingType, string newContract )
    {
        var exportToDecorate = exportDefs.Single( d => d.ContractName == myContractName );
        exportDefs.Remove( exportToDecorate );

        var exportDef = ReflectionModelServices.CreateExportDefinition(
            new LazyMemberInfo( exportingType ),
            newContract,
            new Lazy<IDictionary<string, object>>( () => exportToDecorate.Metadata ),
            null );

        exportDefs.Add( exportDef );
    }
}
公共类DecoratorChainCatalog:ComposablePartCatalog
{
私有列表MyDecorchain;
私人清单;
私有字符串myContractName;
公共装饰Chaincatalog(类型合同)
:此(AttributedModelServices.GetContractName(合同))
{
}
公共装饰Chaincatalog(字符串合同)
{
合同。要求不为空(合同,简称“合同”);
myContractName=合同;
mydecorchain=新列表();
myParts=新列表();
}
公共无效添加(类型)
{
Contract.Invariant(!myParts.Any(),“不支持重新编译”);
mydecorchain.Add(类型);
}
公共可更换部件
{
得到
{
复合生态();
返回myParts.AsQueryable();
}
}
[安全性安全关键]
私有无效成分分解()
{
if(myParts.Any())
{
返回;
}
Trace.WriteLine(!!ComposeDecoration!!”);
var合同=新列表();
foreach(myDecoratorChain中的变量类型)
{
var originalPart=AttributedModelServices.CreatePartDefinition(类型,null);
var importDefs=originalPart.ImportDefinitions.ToList();
if(type!=mydecorchain.First())
{
重写合同(importDefs,contracts.Last());
}
var exportDefs=originalPart.ExportDefinitions.ToList();
if(type!=mydecorchain.Last())
{
contracts.Add(Guid.NewGuid().ToString());
重写合同(exportDefs,type,contracts.Last());
}
//当我们将其传递给下面的lazy时,我们必须将其复制到局部变量,否则我们将使用循环迭代器变量创建一个闭包
//这将导致更改实际的零件类型
var partType=type;
var part=ReflectionModelServices.CreatePartDefinition(
新的惰性(()=>partType),
ReflectionModelServices.IsDisposalRequired(原始部分),
新的惰性(()=>importDefs),
新的Lazy(()=>exportDefs),
new Lazy(()=>new Dictionary()),
无效);
添加(部分);
}
//不可能再添加了
mydecorchain=null;
}
[安全性安全关键]
私有合同(IList importDefs,字符串newContract)
{
var importtodecoration=importDefs.Single(d=>d.ContractName==myContractName);
importDefs.移除(importDefs);
Contract.Invariant(importDepartment.Cardinality==ImportCardinality.ExactlyOne,“基数装饰”+importDepartment.Cardinality+“不支持”);
Contract.Invariant(ReflectionModelServices.IsImportingParameter(ImportToDecoration),“不支持属性注入的装饰”);
var param=ReflectionModelServices.GetImportingParameter(ImportToDetaction);
var importDef=ReflectionModelServices.CreateImportDefinition(
param,
新合同,
AttributedModelServices.GetTypeIdentity(param.Value.ParameterType),
Enumerable.Empty(),
重要性。基数,
创意政策,任何,
无效);
importDefs.Add(importDef);
}
[安全性安全关键]
私有合同(IList exportDefs,类型exportingType,字符串newContract)
{
var exportToDecorate=exportDefs.Single(d=>d.ContractName==myContractName);
exportDefs.Remove(exportToDecorate);
var exportDef=ReflectionModelServices.CreateExportDefinition(
新LazyMemberInfo(导出类型),
新合同,
新的延迟(()=>exportToDecorate.Metadata),
无效);
exportDefs.Add(exportDef);
}
}

另请参见:

您显示的是
IExtension
,但是
IBaseExtension
是从哪里来的?您所说的“现在当
public class DecoratorChainCatalog : ComposablePartCatalog
{
    private List<Type> myDecoratorChain;
    private List<ComposablePartDefinition> myParts;

    private string myContractName;

    public DecoratorChainCatalog( Type contract )
        : this( AttributedModelServices.GetContractName( contract ) )
    {
    }

    public DecoratorChainCatalog( string contract )
    {
        Contract.RequiresNotNullNotEmpty( contract, "contract" );

        myContractName = contract;

        myDecoratorChain = new List<Type>();
        myParts = new List<ComposablePartDefinition>();
    }

    public void Add( Type type )
    {
        Contract.Invariant( !myParts.Any(), "Recomposition not supported" );

        myDecoratorChain.Add( type );
    }

    public override IQueryable<ComposablePartDefinition> Parts
    {
        get
        {
            ComposeDecoration();
            return myParts.AsQueryable();
        }
    }

    [SecuritySafeCritical]
    private void ComposeDecoration()
    {
        if ( myParts.Any() )
        {
            return;
        }

        Trace.WriteLine( "!! ComposeDecoration !!" );

        var contracts = new List<string>();
        foreach ( var type in myDecoratorChain )
        {
            var originalPart = AttributedModelServices.CreatePartDefinition( type, null );

            var importDefs = originalPart.ImportDefinitions.ToList();

            if ( type != myDecoratorChain.First() )
            {
                RewriteContract( importDefs, contracts.Last() );
            }

            var exportDefs = originalPart.ExportDefinitions.ToList();

            if ( type != myDecoratorChain.Last() )
            {
                contracts.Add( Guid.NewGuid().ToString() );
                RewriteContract( exportDefs, type, contracts.Last() );
            }

            // as we pass it to lazy below we have to copy it to local variable - otherwise we create a closure with the loop iterator variable
            // and this will cause the actual part type to be changed
            var partType = type;
            var part = ReflectionModelServices.CreatePartDefinition(
                new Lazy<Type>( () => partType ),
                ReflectionModelServices.IsDisposalRequired( originalPart ),
                new Lazy<IEnumerable<ImportDefinition>>( () => importDefs ),
                new Lazy<IEnumerable<ExportDefinition>>( () => exportDefs ),
                new Lazy<IDictionary<string, object>>( () => new Dictionary<string, object>() ),
                null );

            myParts.Add( part );
        }

        // no add possible any longer
        myDecoratorChain = null;
    }

    [SecuritySafeCritical]
    private void RewriteContract( IList<ImportDefinition> importDefs, string newContract )
    {
        var importToDecorate = importDefs.Single( d => d.ContractName == myContractName );
        importDefs.Remove( importToDecorate );

        Contract.Invariant( importToDecorate.Cardinality == ImportCardinality.ExactlyOne, "Decoration of Cardinality " + importToDecorate.Cardinality + " not supported" );
        Contract.Invariant( ReflectionModelServices.IsImportingParameter( importToDecorate ), "Decoration of property injection not supported" );

        var param = ReflectionModelServices.GetImportingParameter( importToDecorate );
        var importDef = ReflectionModelServices.CreateImportDefinition(
            param,
            newContract,
            AttributedModelServices.GetTypeIdentity( param.Value.ParameterType ),
            Enumerable.Empty<KeyValuePair<string, Type>>(),
            importToDecorate.Cardinality,
            CreationPolicy.Any,
            null );

        importDefs.Add( importDef );
    }

    [SecuritySafeCritical]
    private void RewriteContract( IList<ExportDefinition> exportDefs, Type exportingType, string newContract )
    {
        var exportToDecorate = exportDefs.Single( d => d.ContractName == myContractName );
        exportDefs.Remove( exportToDecorate );

        var exportDef = ReflectionModelServices.CreateExportDefinition(
            new LazyMemberInfo( exportingType ),
            newContract,
            new Lazy<IDictionary<string, object>>( () => exportToDecorate.Metadata ),
            null );

        exportDefs.Add( exportDef );
    }
}