如何编写转换器类?如何有效地编写映射规则?

时间:2012-06-26 19:14:08

标签: c# design-patterns architecture mapping converter

我有一个很大的A级,有很多成员,我有一个很大的B级 可以在拥有A对象时构建。拥有时可以构建A对象 一个B对象。我需要它们两个,因为A是一种ViewModel,它有验证 和B是图形描述,可以很容易地绘制。

如何进行此转换?

这是一个例子,用来说明我想做的事情:

class A
{
    string s;
    string t;
    string u;
    string v;

    enum a;
    enum b;
    enum c;
    enum d;
    enum e;

    Dictionary<enum, string> dict;
}


class B
{
    string someString; // is essentially A.a + A.b + A.c + A.s with some rules.
    int someValue; // is essentially dict.TryGetValue(enum.Entry);
    string anotherString;
    // ... and lots of others
}

当然,做一些映射很简单,并构建一个B对象, 写简单B =&gt;并不是很难通过反转映射 建立A =&gt;的规则乙

所以问题是:

  • 是否有任何众所周知的模式可以实现这一目标?
  • 是否有默认的C#方式来做这些事情?

写下这样的东西似乎不合适, 它以数百行代码结束。

我想到了某些部件的转换器类, 像SomeStringConverter,SomeValueConverter,......

  • 我如何抽象出所需的A成员  做映射的规则。
  • 我如何编写这些规则以尽可能最简单  做A =&gt;的方式B和B =&gt;甲

修改 这里的模式是“最佳实践”,而不是“GoF设计模式”

B类中的SomeString是某种“选择器”,它选择绘图 选项,它总是25个字符长,A类中的枚举选择 这些字符,但在大多数情况下不是1对1。

让我们举例说:A.a =“Filled”,A.b =“SingleCoordinate”,A.c =“DrawHints” 会产生像SomeString =

这样的东西
 "Y**D***RR****---***---***"

即。组合对于获得这样的字符串很重要,但是从组合中可以看出 您可以派生必须在A对象中设置的枚举。

编辑2:

我对两种方式使用映射规则的方式特别感兴趣,即 A.a =“Filled”结合A.b =“SingleCoordinate”与A.c =“DrawHints”组合将导致(部分字符串)"Y**D***RR",而该部分字符串也意味着 A.a必须设置为“填充”等等。

5 个答案:

答案 0 :(得分:4)

听起来像A更像是数据模型而B更像是View Model。我不认为这种情况有一种普遍接受的“模式” - 主要是因为这种配对背后的原因差异很大,最好的模式在很大程度上取决于预期用途。

那就是说,因为他们紧紧地联系在一起,所以我倾向于让一个班级从属于另一个班级。在这种情况下,由于A更直接,我可能使用A作为B的数据容器。即将私有成员A作为B类中的字段,并将B类中的所有属性引用到A类直接更新属性而不是拥有自己的私人领域。然后,您可以在B类上拥有一个公共属性,以便在需要时公开A类的私有成员。我可能保持只读,但这可能不是很重要(取决于你使用B类和任何可能的绑定关系)。换句话说,我会在B类上创建一个接受A类作为参数的构造函数。然后将传递的A值分配给B类上的私有类A成员。

所有这一切的结果是维持A类对B类的无知 - 如果你有一个ViewModel情况的真实用例,这将变得有用。如果您确定A类是您需要的更真实的ViewModel,那么请反转上面的内容,以便B类对A类一无所知。

答案 1 :(得分:3)

  

是否有任何众所周知的模式可以实现这一目标?

这取决于你对模式的意思。我会想到DecoratorAdapter模式,但这两种模式都不适用于将类型批量映射到不同类型。

  

是否有默认的C#方式来做这些事情?

不,没有。但像Automapper这样的图书馆肯定会让生活更轻松。

答案 2 :(得分:0)

工厂+可能的门面

您希望协调从A中构建B或从B中协调构建B.这就要求您需要复杂的逻辑来执行此操作。

要从A构建B,要么在B(Factory)上实现静态方法,要么创建一个从B继承的新类C,并将A作为参数作为其构造函数(Facade)。

工厂:http://en.wikipedia.org/wiki/Factory_method_pattern(与您的情况不完全匹配)

Facade:http://en.wikipedia.org/wiki/Design_Pattern_-_Facade(也不是完全匹配)

答案 3 :(得分:0)

一些想法:

A)将B改为A实现的接口。这将允许您将B的属性直接“映射”到A的属性,而无需重新创建它们。如果B具有A不应该具有的属性(或者具有组合多个A的属性),则可以将访问修饰符设置为private * - 意味着该属性仅通过接口可见(以便不会混淆或混乱A)的实现。

B)使用伪适配器/包装器模式。 B,给定类型A的构造函数参数,可以引用回A的属性等。其中B不同,它可以实现自己的逻辑。

两个复杂对象之间的映射需要一些复杂的思考。总会有特殊情况,副作用和选择需要思考和平衡利弊。 (例如,在字符串和int之间进行转换会引入各种问题 - 如何处理千位分隔符,如何处理不同的文化等等。)从阅读您的具体情况来看,我看不到一种简单或快捷的方式处理映射 - 您将拥有一个基于所涉及的所有因素的方法,可能在此处发布的内容太多了。

编辑: *我应该注意到这是我在几个VB项目中所做的。我认为这在C#中是合法的,但我没有尝试过。

答案 4 :(得分:0)

我为解决这个问题做了什么:

  1. 写了一个BiMap(在这个问题的帮助下,老版SO)。

  2. 将映射插入其中(Key中的所有值组合,“Value”中的结果键,以及指定字符串索引的BitArray) 由该映射定义。

  3. 写了一些代码来计算从中得到的整体字符串,作为映射 只会给出部分字符串。

  4. 一对一的映射是微不足道的。

  5. 这样我就可以在两种方式中使用映射。给定一个字符串,我仍然有一个相当 昂贵的搜索(因为我必须使用BitArray作为掩码来计算存储的字符串)

    目前看起来效果很好,但我还没完成。

    谢谢大家的好主意和方法!也许AutoMapper可以做到 这一点,但我现在没有太多时间阅读和尝试新技术。

    如果有人可以提供一些关于如何在Automapper上执行此操作的相关示例, 我会接受它作为答案(因为我已经喜欢AutoMapper)。

    例如,让我们说:3个枚举,5个值到一个固定长度的字符串 一个固定长度的字符串到3个枚举,有5个值(与上面相反)。

    作为一个例子:

    A.a && B.o && C.y ==> "**A**********************"
    A.a && B.p && C.y ==> "**B**********************"
    A.b && B.o && C.y ==> "*****X*******************"
    A.b && B.o && C.z ==> "*****W*******************"
    

    Automapper可以实现这样的目标吗?