关于MEF战略和结构的问题

时间:2013-10-02 07:28:17

标签: .net prism mef composition modularity

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

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

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

1 个答案:

答案 0 :(得分:4)

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

如何处理元数据? MEF提供元数据的导出,这似乎是合理的使用方法。也许我没有完全理解它,但我在MEF元数据导出方面做得非常糟糕。据我所知,MEF将元数据存储为键值对,其中键是字符串。

即使您使用键入的元数据导出和使用功能,元数据也不是真正的类型安全。假设您有一个名为'PropertyA'的属性的接口'IMetadata',并且您注册了一个类型(为了创造性,我们称之为Foo),该类型用a中的相应属性修饰,MEF调用 typesafe ,方式(实现IMetadata的元数据)。现在假设您有第二个元数据接口“IMetadataB”,它还有一个名为PropertyA的属性。如果您现在请求使用元数据Foo解析IMetadataB,您将首先获得您注册的实例,因为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中使用此元数据。没有什么会混淆,因为你拥有一种类型的元数据用于拥有一个属性的所有东西(没有其他类型)。

这个解决方案不适合一切,但我喜欢它,你的问题是展示它的好时机。希望能帮助到你!