【问题标题】:Questions on MEF strategy and structure关于 MEF 战略和结构的问题
【发布时间】:2013-10-08 12:59:39
【问题描述】:

我的任务是模块化一个 C# 应用程序,它是一个非常大的 Delphi 应用程序的重写(数据库有 249 个表!)。业务限制禁止对 .NET 进行完全重新设计和更好的整体架构,因此我们基本上只是在 C# 中为 Delphi 应用程序的模块逐步重写模块。在完成之前,该套件将包含未决的重写以及我想使用 MEF 集成的 C# 应用程序模块。

该应用程序关注考勤和访问控制,并具有“员工休假”和“访客”等多个业务领域。我认为这些应该是单独的项目,我们可以在其中换出一个重写的 C# 项目,并将其导入到 MEF 容器中。每个项目将导出一个IBusinessArea,作为最高级别的定义,然后这些将导出标准的共享接口,如IService,介绍业务领域中可用的服务,如CreateEmployee。每个服务都会是一个类,以规范服务与容器的接口,并包含服务元数据,例如服务的Command、谁可以使用该服务的数据等。

我是否朝着正确的方向前进?如果是,我如何将 IBusinessAreaIService 元数据存储和公开为类,而不是大量无类型的元数据属性?

【问题讨论】:

    标签: .net prism mef composition modularity


    【解决方案1】:

    到目前为止,你所说的一切对我来说都是合理的。您将某些区域模块化,在不同的抽象级别上定义接口,并使用不同的接口导出每个模块,即每个模块将注册为其实现的多个接口。您将能够根据您需要的抽象级别解析您的模块,获得所有服务、所有业务领域等。所以,在我看来,您正朝着正确的方向前进。

    如何处理元数据? MEF 提供元数据的导出,这似乎是一个合理的使用方法。也许我没有完全明白,但我在 MEF 元数据导出方面的经历非常糟糕。据我回忆,MEF 将元数据存储为键值对,其中键是字符串。

    即使您使用类型化元数据导出和使用功能,元数据也不是真正类型安全的。假设您有一个带有名为“PropertyA”的属性的接口“IMetadata”,并且您注册了一个类型(为了创造性,我们将其称为Foo),该类型在a中装饰有相应的属性,MEF称之为typesafe ,方式(元数据实现IMetadata)。现在假设您有第二个元数据接口“IMetadataB”,它也有一个名为PropertyA 的属性。如果您现在请求使用元数据 IMetadataB 解析 Foo,您将首先获得您注册的实例,因为 MEF 对存在于元数据键值对中的 PropertyA 感到满意,并构建了一个相应的代理元数据类型,实现IMetadataB

    长话短说,也许我对 MEF 不公平,但我停止使用 MEF 内置的元数据支持,并建议您也这样做。

    由于我正在处理非常复杂且冗长的元数据,包括我希望与导出的类紧密耦合的类文档,我开发了一个对我来说非常有效的系统,虽然它有点有点不合常规:

    基本上,我为我的元数据定义了一个接口和一个基类,比如MetadataBase 和一个名为Description 的字符串属性。

    public class MetadataBase : IMetadata
    {
        public string Description { get; set; }
    }
    

    之后,对于我想要为其获取元数据的每个类,我从这个基类派生一个类 (FooMetadata) 并在 XAML 中部分定义它。然后,在 XAML 中,我定义属性的类特定值,例如:

    <md:MetadataBase.Description>
        The description of my class goes here
    </md:MetadataBase.Description>
    

    使用自定义属性,我将元数据类型与我的实际类相关联:

    [Export(typeof(IFoo))]
    [AssociatedMetadata(typeof(FooMetadata))]
    public class Foo : IFoo
    {
        // Whatever
    }
    

    对象的扩展方法让您可以通过反射读取元数据:

    public static IMetadata GetMetadata(this object objectWithMetadata)
    {
         // Read attribute type
         // Create instance of the metadata type, i.e. FooMetadata
         // A caching mechanism can be implemented, if needed, but, honestly,
         // my really big metadata objects including images and stuff like this
         // are created within 3-5 ms
         // Return this instance
    }
    

    现在,你基本上就在那里了,你可以读取任何具有如下元数据的对象的元数据:

    var myObjectsMetadata = myObject.GetMetadata();
    

    当您让AssociatedMetadataAttribute 实现接口并使用此接口的元数据注册您的类型时,您可以在 MEF 中使用此元数据。什么都不会混淆,因为您拥有一种类型的元数据,用于包含一个属性而没有其他任何内容(类型)的所有内容。

    此解决方案并不是解决所有问题的正确方法,但我喜欢它,您的问题是展示它的好时机。希望能帮助到你!

    【讨论】:

    • 对我而言,MEF 导出元数据最强大的功能是您无需创建导出部分即可访问它们。对于加载项方案,这非常有用。您关于类型安全的观点是有效的,应该在 MEF 的文档中明确说明,以便新手更轻松。也就是说,对于大多数应用程序来说,一两个元数据类就足够了。如果我没记错的话,您的方法是使用 IMetadata。不过,我在 WPF 方面没有经验,无法判断您的方法是否可以用 MEF 导出元数据替换。
    • @PanosRontogiannis,正确,我使用的是一个元数据接口。您仍然可以通过 MEF 导出元数据并访问它,而无需实际解析导出的部分。对我来说,这是两全其美。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多