ImportMany 未导入元数据

发布于 2024-09-17 08:30:52 字数 1579 浏览 2 评论 0 原文

几天来我一直在尝试解决这个问题,但没有运气。

我正在尝试使用 [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 永远不会被填充。我没有收到构图错误。

我认为这可能与Lazy<>有关,所以我尝试了

public ObservableCollection<IEditorSystem> EditorSystemList

也没有运气。

我能想到的唯一复杂之处是我使用的是 Cinch,它使用 MEFedMVVM,它也使用 MEF。我不认为它会干扰,但我不太确定。

我想我做错了,有人能理解吗?

更新:

实现一个新的 IComposer,其中包含您需要的目录。

不过,ImportMany 仍然失败,但只有当我尝试用它导入元数据时才会失败。元数据只是几个字符串,据我所知,遵循示例。

终于找到了原因:IEditorSystem 的实现位于单独的 DLL 中,如前所述。 但是,任何新构建的 dll 都不会复制到主项目的输出子目录中。 我手动复制了第一个,但忘记将构建后副本添加到 dll 项目中。 哦,好吧,学到了很多关于 MEF 的东西,所以没有完全浪费时间:)

I've been trying to figure this for a few days now, with no luck.

I'm trying to use the [ImportMany] to import from a directory full of DLL's with exports of type IEditorSystem, that have custom metadate of type IEditorSystemMetadata. I'd like to get the metadata first, and push it out to some textboxs etc so the user can choose which EditorSystem to use, and when selected, load that system...

I've been following examples as best as I can, here's what I have so far.

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

This is what it should be importing:

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

and the startup:

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

I can see in the Catalog.Parts both the MyEditorSystem and the viewmodel that has the ImportMany, but EditorSystemList never gets populated. I get no Composition errors.

I thought it might have something to do with the Lazy<>, so i tried

public ObservableCollection<IEditorSystem> EditorSystemList

No luck either.

The only complication I can think of is that I'm using Cinch, which uses MEFedMVVM, which also uses MEF. I don't think it interferes, but I'm not really sure.

I figure I'm doing it wrong, can anyone make sense of this?

Update:

Implement a new IComposer, with exactly the catalog you need.

ImportMany is still failing though, but only when I try to import metadata with it. The metadata is just a couple of strings, and as far as I am able to determine, follows the examples.

FINALLY found the cause: The implementations of IEditorSystem are in a seperate DLL, as noted before.
However, any new builds of the dll are not copied to the output subdir of the main project.
I had copied the first one manually, and forgot to add a post-build copy to the dll project.
Oh well, learned a bunch of stuff about MEF, so not completely wasted days :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花期渐远 2024-09-24 08:30:52

在没有看到您的代码的情况下,我相信您需要更改的只是

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

Without seeing your code, I believe all you need to change is

public ObservableCollection<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList  

should be

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

Here is a sample:

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; }
}
我还不会笑 2024-09-24 08:30:52

也许我的解决方案也能解决您的问题。

我正在努力尝试发现问题。

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

Metadata接口应该只包含一个相同类型的属性:

int,bool,string等。如果你放Int的两个属性,例如,ImportMany>;不起作用,并且始终返回 0。

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

例如,

公共接口 IMyExportMetadata
{
int a {获取;}
字符串 b {获取; }
布尔 c {获取;}
}

[导出(类型(IMyInterface))
[导出元数据(“a”,0)]
[导出元数据(“b”,“字符串”)]
[导出元数据(“c”,true)]
公共类 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;
    }
     */
}

Maybe my solution solves your problem too.

I was working hard trying to discover the problem.

then I got the following solution:

Metadata interface should contain only one property of the same type:

int, bool, string, etc. If you put two properties of Int, for example, the ImportMany> will not work and it will always return 0.

for each property of the interface, you must put the ExportMetadata Attribute at the exported class to.

for example,

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
{
}

to work with multiple booleans, for example, you must create a custom export attribute implementing the metadata interface like this:

[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;
    }
     */
}
虐人心 2024-09-24 08:30:52

也许我的解决方案也能解决您的问题。

我正在努力尝试发现问题。

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

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

intboolstring等。如果你输入两个 int 属性,例如,ImportMany> 将不起作用,并且始终返回 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
{
}

Maybe my solution solves your problem too.

I was working hard trying to discover the problem.

then I got the following solution:

Metadata interface should contain only one property of the same type:

int, bool, string, etc. If you put two properties of int, for example, the ImportMany<Lazy<t,m>> will not work and it will always return 0.

for each property of the interface, you must put the ExportMetadata Attribute at the exported class to.

for example,

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
{
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文