繁体   English   中英

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

[英]How do I combine the Decorator pattern with C# MEF?

我正在尝试增强当前使用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()); 

     }
}

但是,如果我想为IExtension或BaseExtension实现特定的装饰器,则不知所措,我应该将它们放置在容器中,或者如何将属性放置在装饰器上,以便所有原始IExtension具体类都被加载并执行其他行为。 IExtension装饰器的示例:

// do I put an attribute here? 
// if an attribute is put here, how does the MEF container call it?
public BatchableExtension : BaseExtension 
{
     private IExtension extension = null; 


     public BatchableExtension( IExtension extension) 
     {
        this.extension = extension; 
     }

     public override Object Execute() 
     {
        this.extension.Execute(); 
        doSomeBatchSpecificOperation(); 
     }
}

// do I put an attribute here? 
// if an attribute is put here, how does the MEF container call it?
public  MonitoringExtension : BaseExtension 
{
     private IExtension extension = null; 


     public MonitoringExtension( IExtension extension) 
     {
        this.extension = extension; 
     }

     public override Object Execute() 
     {
        this.extension.Execute(); 
        doSomeMonitoringSpecificOperation(); 
        doSomeMoreBehaviors(); 
     }

有人可以帮忙吗? 我想确保当容器提取扩展名时,也取决于传递的参数(例如,如果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;
}

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

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 );
    }
}

另请参阅: http : //blade.codeplex.com/SourceControl/latest#src/Blade.Core/Composition/DecoratorChainCatalog.cs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM