2010-11-21 74 views
4

我正在尋找使用MEF插件系統爲我正在建設的應用程序。我希望每個組件都有一個(GUID)標識符,我希望能夠查找它們。但是,使用導出部分時,此ID也是非常有用的。MEF元數據從出口部分

有沒有一種方法,我可以有一個元數據屬性,其中包含ID以及導出的部分上的屬性(或方法),缺少開發人員填充兩次或使用反射從屬性中找到它?

回答

7

它很可能是MEF元數據屬性和抽象基類的混合。我會定義我的插件合同是這樣的:

public interface IPluginMetadata 
{ 
    Guid PluginId { get; } 
} 

public interface IPlugin : IPluginMetadata 
{ 
    void Initialise(); 
} 

我已經執行了IPlugin接口也繼承了我們的合同元IPluginMetadata。接下來,我們可以創建自定義導出屬性:

[AttributeUsage(AttributeTargets.Class, Inherit = true), MetadataAttribute] 
public class ExportPluginAttribute : ExportAttribute, IPluginMetadata 
{ 
    public ExportPluginAttribute(string pluginId) : base(typeof(IPlugin)) 
    { 
    if (string.IsNullOrEmpty(pluginId)) 
     throw new ArgumentException("'pluginId' is required.", "pluginId"); 

    PluginId = new Guid(pluginId); 
    } 

    public Guid PluginId { get; private set; } 
} 

你並不需要裝飾合同IPluginMetadata元數據的導出屬性,如MEF無論如何都會項目的屬性,但我更喜歡這樣做,因此,如果我確實引入了對元數據合同的更改,然後我的導出屬性也應該更新。沒有傷害,沒有犯規。

一旦我們做到了這一點,我們可以定義從一個抽象基類來實現我們的插件合同:

public abstract class PluginBase : IPlugin 
{ 
    protected PluginBase() 
    { 
    var attr = GetType() 
     .GetCustomAttributes(typeof(ExportPluginAttribute), true) 
     .Cast<ExportPluginAttribute>() 
     .SingleOrDefault(); 

    PluginId = (attr == null) ? Guid.Empty : attr.PluginId; 
    } 

    public virtual Guid PluginId { get; private set; } 

    public abstract void Initialise(); 
} 

然後,我們可以獲取自定義的通過抽象類的構造屬性,並申請財產因此。我們可以這樣做:

public IPlugin GetPlugin(Guid id) 
{ 
    var plugin = container 
    .GetExports<IPlugin, IPluginMetadata>() 
    .Where(p => p.Metadata.PluginId == id) 
    .Select(p => p.Value) 
    .FirstOrDefault(); 

    return plugin; 
} 

而且也:

[ExportPlugin("BE112EA1-1AA1-4B92-934A-9EA8B90D622C")] 
public class MyPlugin : PluginBase 
{ 
    public override Initialise() 
    { 
    Console.WriteLine(PluginId); 
    } 
} 

我們可以看到,出PluginId暴露既通過導出的元數據,以及我們的插件的屬性。

這段代碼都沒有經過測試,但我希望它能將您推向正確的方向。

+0

+1非常漂亮的想法和實施! – 2010-11-21 12:23:34

+1

這就是我一直在想我必須去的地方,儘管我會指出你不能把Guid作爲元數據對象的屬性類型。不是一個巨大的交易,我只是使用CodeContract在屬性的ctor中執行它 – 2010-11-22 22:24:02

0

把GUID在一個常數,並使用它既有財產和元數據:

[Export(typeof(IFoo))] 
[ExportMetadata("GUID", _guid)] 
public class Foo : IFoo 
{ 
    private const string _guid = "abc"; 

    public string Guid { get { return _guid; } } 
} 

請注意,您不能使用Guid類型,而不是string,因爲這是不被許可const關鍵字。