[英]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.