6

我有一个很大的 A 类,有很多成员,我有一个很大的 B 类,可以在拥有 A 对象时构建。拥有 B 对象时可以构建 A 对象。我需要它们,因为 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对象,通过颠倒构建A => B的规则来写普通的B => A映射并不难

所以问题是:

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

写下类似这样的简单内容似乎不合适,它最终会变成数百行代码。

我考虑了一些用于部件的转换器类,例如 SomeStringConverter、SomeValueConverter、...

  • 我如何将 A 的所需成员与规则一起抽象出来以进行映射。
  • 我如何编写这些规则以最简单的方式来执行 A => B 和 B => A。

编辑: 这里的模式是指“最佳实践”而不是“GoF 设计模式”

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

例如:Aa = "Filled", Ab = "SingleCoordinate", Ac = "DrawHints" 会产生类似 SomeString =

 "Y**D***RR****---***---***"

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

编辑2:

我对两种方式都使用我的映射规则的方式特别感兴趣,即 Aa = "Filled" 结合 Ab = "SingleCoordinate" 结合 Ac = "DrawHints" 将导致 (partial string) "Y**D***RR",并且部分字符串也意味着必须将 Aa 设置为“已填充”等等。

4

5 回答 5

4

在我看来,A 更像是数据模型,而 B 更像是视图模型。对于这种情况,我不认为有一个普遍接受的“模式”——主要是因为这种配对背后的原因千差万别,而最佳模式很大程度上取决于预期用途。

就是说,由于它们紧密相连,我倾向于让一个班级从属于另一个班级。在这种情况下,由于 A 更简单,我可能会使用 A 作为 B 的数据容器。即将私有成员 A 作为 B 类中的字段,并且 B 类中的所有属性直接引用 A 类——更新A 而不是背后有自己的私有领域。然后,您可以在 B 类上拥有一个公共属性,如果需要,该属性会公开 A 类的私有成员。我可能会保持只读状态,但这可能并不重要(取决于您对 B 类的使用和任何可能的绑定关系)。反过来,我会在 B 类上创建一个构造函数,该构造函数接受 A 类作为参数。然后将传递的 A 值分配给类 B 上的私有类 A 成员。

所有这些的结果是保持 A 类对 B 类的无知——如果你有一个 ViewModel 情况的真实用例,这将变得很有用。如果您确定 A 类是您需要的更真实的 ViewModel,则将上述相反,使 B 类是 A 类的无知者。

于 2012-07-03T21:15:56.343 回答
3

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

这取决于你所说的模式是什么意思。Decoratoror模式浮现在Adapter脑海中,但都不是为了将类型批发映射到不同类型。

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

不,没有。但是像Automapper这样的库确实让生活更轻松。

于 2012-06-26T19:16:38.710 回答
0

工厂 + 可能的门面

您想协调从 A 构建 B 或从 B 构建 A。这表明您需要复杂的逻辑才能做到这一点。

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

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

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

于 2012-06-29T06:42:41.027 回答
0

几个想法:

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

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

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

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

于 2012-07-02T16:12:55.147 回答
0

我为解决这个问题所做的工作:

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

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

  3. 编写了一些代码来计算由此产生的整体字符串,因为映射只会给出部分字符串。

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

这样我就可以以两种方式使用映射。给定一个字符串,我仍然有一个相当昂贵的搜索(因为我必须使用 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 能做到这样的事情吗?

于 2012-07-03T21:02:47.300 回答