2010-09-02 72 views
5

我一直在试图找出这几天,没有运气。ImportMany与元数据无法导入

我试图使用[ImportMany]从一个完整的DLL目录中导入类型为IEditorSystem的导出,该导入具有IEditorSystemMetadata类型的自定义元字体。我想首先获取元数据,并将其推送到某些文本框等,以便用户可以选择使用哪个EditorSystem,并在选择时加载该系统...

我一直在关注以下示例尽我所能,这是迄今为止我所拥有的。

[ImportMany] 
public ObservableCollection<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList 

这是它应该导入:

[Export(typeof(IEditorSystem))] 
    [SignalSystemData("Very Very Long Name", "Short Name")] 
    public class MyEditorSystem: IEditorSystem 
    { 
     public MyEditorSystem() 
     { 
     } 
    } 

和启动:

AggregateCatalog Catalog = new AggregateCatalog(
       new DirectoryCatalog(@".\EditorSystems"), 
       new AssemblyCatalog(Assembly.GetExecutingAssembly())); 
      CompositionContainer Container = new CompositionContainer(Catalog); 
      Container.ComposeParts(this); 

我可以在Catalog.Parts同时看到MyEditorSystem并且具有视图模型ImportMany,但EditorSystemList永远不会被填充。我没有得到组合错误。

我认为它可能有一些做的懒惰<>,所以我尝试

public ObservableCollection<IEditorSystem> EditorSystemList 

没有任何运气。

我能想到的唯一复杂因素是我使用的是使用MEFedMVVM的Cinch,它也使用MEF。我不想认为它干涉,但我不确定。

我想我做错了,任何人都可以理解这一点吗?

更新:

实现新的IComposer,与正是你所需要的目录。

虽然ImportMany仍然失败,但只有当我尝试导入元数据时才会这样。元数据仅仅是一对字符串,并且就我能够确定的而言,遵循这些示例。

最终找到原因:如前所述,IEditorSystem的实现位于独立的DLL中。 但是,任何新版本的dll都不会复制到主项目的输出子目录中。 我已经手动复制了第一个,并忘记将后生成的副本添加到dll项目。 哦,学到了一堆关于MEF的东西,所以不能完全浪费天:)

回答

1

没有看到你的代码,我相信所有你需要改变的是

public ObservableCollection<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList 

应该

public IEnumerable<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList; 

这里有一个例子:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var c = new Class1(); 
     var v = c.EditorSystemList; 
     foreach (var lazy in v) 
     { 
      if (lazy.Metadata.LongName == "Very Very Long Name") 
      { 
       var v2 = lazy.Value; 
       // v2 is the instance of MyEditorSystem 
      } 
     } 
    } 
} 

public class Class1 
{ 
    [ImportMany] 
    public IEnumerable<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList; 

    public Class1() 
    { 
     var catalog = new AggregateCatalog(
      new AssemblyCatalog(Assembly.GetExecutingAssembly())); 
     var container = new CompositionContainer(catalog); 
     container.ComposeParts(this); 
    } 
} 

[Export(typeof(IEditorSystem))] 
[SignalSystemData("Very Very Long Name", "Short Name")] 
public class MyEditorSystem : IEditorSystem { } 

public interface IEditorSystem { } 

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
public class SignalSystemDataAttribute : ExportAttribute 
{ 
    public SignalSystemDataAttribute(string longName, string shortName) 
     : base(typeof(IEditorSystem)) 
    { 
     LongName = longName; 
     ShortName = shortName; 
    } 
    public string LongName { get; set; } 
    public string ShortName { get; set; } 
} 

public interface IEditorSystemMetadata 
{ 
    string LongName { get; } 
    string ShortName { get; } 
} 
+0

我将其更改为IEnumerable,但导入从未似乎完成,EditorSystemList保持在[0] ... – Kage 2010-09-03 03:48:55

+0

您是否尝试运行上面的确切代码?你应该能够创建一个控制台应用程序来测试。 – JoshVarga 2010-09-03 15:06:05

+0

是的,控制台版本可以工作,但它看起来可能是由于MEFedMVVM搞砸了,会更新 – Kage 2010-09-04 09:28:42

0

也许我解决方案也解决了你的问题。

我一直在努力尝试发现问题。

然后我得到了以下解决方案:

元数据接口应当只包含一个相同类型的属性:如果你把int两个属性,例如

intboolstring等, ImportMany<Lazy<t,m>>将不起作用,它将始终返回0.

对于接口的每个属性,必须将ExportMetadata属性放在导出的类上。

例如,

public interface IMyExportMetadata 
{ 
    int a {get;} 
    string b {get;} 
    bool c {get;} 
} 

[Export(typeof(IMyInterface)) 
[ExportMetadata("a", 0)] 
[ExportMetadata("b", "string")] 
[ExportMetadata("c", true)] 
public class myExportedClass: IMyInterface 
{ 
} 
1

也许我的解决方案解决你的问题了。

我一直在努力尝试发现问题。

然后我得到了以下解决方案:

元数据接口应当只包含一个相同类型的属性:

整型,布尔,字符串,等等。如果你把Int的两个属性,例如, ImportMany>将不起作用,它将始终返回0.

对于接口的每个属性,必须将ExportMetadata属性置于导出的类上。

例如,

公共接口IMyExportMetadata { INT一个{获得;} 串B {得到; } 布尔13 C {获得;} }

[导出(typeof运算(IMyInterface的)) [ExportMetadata( “一”,0)] [ExportMetadata( “B”, “串”)] [ExportMetadata( “C”,真)] 公共类myExportedClass:IMyInterface的 { }

与多个布尔工作,例如,你必须创建一个自定义导出属性实现元数据接口是这样的:

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 
public class ExportUserPartAttribute : ExportAttribute, IUserPartMetadata 
{ 
    #region Implementation of IUserPartMetadata 

    public int TipoPart { get; set; } 
    public string Regiao { get; set; } 
    public bool IsLogin { get; set; } 
    public bool IsMenu { get; set; } 
    public bool IsHome { get; set; } 
    public bool IsListagem { get; set; } 
    public bool IsFormulario { get; set; } 

    #endregion 

    public ExportUserPartAttribute() 
     : base(typeof(IUserPart)) 
    { 

    } 

    /* 
    public ExportUserPartAttribute(int tipoPart, string regiao) 
     : base(typeof(IUserPart)) 
    { 
     this.TipoPart = tipoPart; 
     this.Regiao = regiao; 
    } 
    */ 
}