【问题标题】:MEF update exported part metadata (the metadata view is invalid because property has a property set method)MEF 更新导出的部件元数据(元数据视图无效,因为属性有属性设置方法)
【发布时间】:2013-08-01 09:44:15
【问题描述】:

我有一个应用程序,我正在使用 MEF 来编写它。我想知道零件导入后是否可以更新元数据信息。

这样做的原因如下:我在 ListBox 中显示导入部件的名称和 typeof(int) 属性,并且在选择相应的 ListBoxItem 之前不会加载它们(非常标准)。现在我想在某个事件引发时更新一个部分的元数据信息,所以 ListBox 中显示的信息类似于“[Part name] ([new number])”。

我将元数据作为定义其信息的接口导入,但是当我将 int 属性设置为可编辑(使用设置的访问器)时,我在合成时收到以下执行:

"The  MetadataView 'myMetadataInterface' is invalid 
 because property 'myInt' has a property set method."

有什么方法可以做到这一点吗?还是只有在创建部件后才读取元数据?

我知道这个问题看起来很奇怪,但这并没有降低它的难度,因此也很有趣 ;-)


编辑(基于李的回答,以便让人们了解问题的核心)

我只想知道是否可以在组成部分之后但在实际加载之前更新元数据属性(HasValue == false)。不用担心过滤或查找部件。

我在导出界面中添加了一个属性,该属性仅用于在UI中表示并进行更新,该属性没有其他功能并且不被它过滤。

谢谢

【问题讨论】:

    标签: c# wpf mef ioc-container


    【解决方案1】:

    元数据过滤和 DefaultValueAttribute

    当您指定元数据视图时,将发生隐式过滤 仅匹配那些包含定义的元数据属性的导出 在视图中。您可以在元数据视图上指定属性是 不需要,通过使用 System.ComponentModel.DefaultValueAttribute。下面你可以看到在哪里 我们在 IsSecure 上指定了默认值 false。这意味着如果 一部分导出 IMessageSender,但不提供 IsSecure 元数据, 那么它仍然会匹配。

    citation

    短版(在问题编辑后编辑)。

    您永远不需要在运行时更新元数据。如果您有一些数据需要更新并且属于 mef 部分,您需要选择通过重新编译来更新它,或者将这些数据存储在 dll 之外的灵活存储中。如果不重新编译,就无法将所做的更改存储在 dll 中,因此这是一个有缺陷的设计。

    以前的帖子。

    更改 视图 上的值会谎报加载的组件。当然,元数据只是返回初始化值的对象的接口;确保您可以在技术上更新这些值,但这不是元数据的目的。

    您不会更改Type 实例的Name 字段。为什么不?因为它是元数据。在运行时更新元数据意味着真实数据实例的性质以某种方式被修改。

    如果可能,这行代码不会引入 Triple 类型。

    typeof(Double).Name = "Triple";
    var IGotATriple = new Triple();
    

    如果您想更改值,您只需使用该信息创建另一个对象并绑定到该对象。元数据已编译。如果您在加载零件后更改它,它不会更改零件源中的任何内容,因此您会撒谎。 (除非您可以访问源代码并在那里更改并重新编译)。

    我们来看一个例子:

    [Export(typeof(IPart))]
    [ExportMetadata("Part Name","Gearbox")]
    [ExportMetadata("Part Number","123")]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class GearBoxPart : Part { public double GearRatio ... }
    

    现在,假设您有一个显示可用部件及其编号的 UI。现在,制造商出于任何原因更改了部件号,而您想要更新它。如果可能,您可能需要考虑将零件编号存储在清单或数据库中。或者,每次零件编号更改时,您都必须重新编译。

    可以重新编译。您有一个执行上述操作的控制器 UI,但不是更新元数据,而是提交重建部件代码文件的请求。该请求将通过解析代码文件、替换部件号、然后发送批量重新编译和重新分发新 dll 来处理。 IMO 做了大量的工作。

    因此,您设置了一个数据库。然后将对象元数据更改为此。

    [ExportMetadata("OurCompanyNamePartNumber","123")]
    

    然后,您就有了一个数据库/清单/xml,它将贵公司设计的唯一永久静态零件编号映射到当前零件编号。控制 UI 中的修改会更新数据库/清单/xml。

    <PartMap>
        <PartMapEntry OurCompanyNamePartNumber="123" ManufacturerPartNumber="456"/>
        ...
    </PartMap>
    

    然后最终用户 UI 按制造商零件号查找零件,mef 代码在 PartMap 中查找以获取 mef 零件号。

    【讨论】:

    • 谢谢你的回答李。我不明白你所说的“所以你会撒谎”是什么意思,愿意解释一下吗?您的最后一条评论是我想要实现的:按需更新与 mef 部分元数据相关的数据……您能举一个简单的例子或指导方针吗?再次感谢。
    • 您的元数据视图描述了您将检索的类型的查询,在运行时更改该查询本质上是对您检索的内容“撒谎”。如果是关于需要更新的类的数据,那么您应该有另一种存储该数据的方法。 mef 元数据不是数据库。
    • 感谢 Lee 更新您的答案,但我认为您在假设某些事情不适用于我的情况。我在元数据中有一个仅用于更新的 int 属性,“过滤器”是由其他属性组成的。此 int 属性仅用于更新显示,无需加载整个部分。我想知道是否可以在不重新加载所有部分的情况下更新一个属性,不要担心“撒谎”。我感谢您在答案中付出的所有努力,为此我投票赞成。问候。
    • @Hannish 好的,所以我查看了您在问题中的编辑,我认为您做错了。您永远不必在运行时更新元数据中的属性。如果这是你想要做的,那就不要。创建另一个对象并将元数据属性复制到其中,然后在运行时更新它。即使你这样做了,除非你重新编译 mef 部分 dll,否则你没有地方保存更改。 这不是元数据是否可以在运行时更新的问题,而是是否应该更新的问题。在这种情况下,如果您希望在不重新编译的情况下更新数据,那么它不应该是元数据。
    • 谢谢李,我认为将元数据复制到另一个对象然后更新该对象的想法可能会奏效。我不太确定是否不应该更新元数据,因为我在元数据中放置了一个属性只是为了更新目的......如果我不打算更新它,那么该属性将不存在。我只是想避免加载一个大对象只是为了在屏幕上显示一个数字。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 2012-09-03
    相关资源
    最近更新 更多