C# 多态对象图之间的转换
冗长的软件架构问题 清晰编辑:我正在尝试转换由以下类型组成的对象图C# 多态对象图之间的转换,c#,architecture,C#,Architecture,冗长的软件架构问题 清晰编辑:我正在尝试转换由以下类型组成的对象图 NodeA,NodeB。。。到由类型组成的对象图,如*My*NodeA,*My*NodeB…,反之亦然。NodeX类型中的属性对应于MyNodeX类型中的类似属性,但在许多情况下,它不仅仅是一个简单的赋值 如果我有两个类似的类结构,如下所示: Mapper.CreateMap<Node,MyNode>(); // no special rules for this map //纯模型,即便于存储的最小信息 abst
NodeA
,NodeB
。。。到由类型组成的对象图,如*My*NodeA
,*My*NodeB
…,反之亦然。NodeX
类型中的属性对应于MyNodeX
类型中的类似属性,但在许多情况下,它不仅仅是一个简单的赋值
如果我有两个类似的类结构,如下所示:
Mapper.CreateMap<Node,MyNode>(); // no special rules for this map
//纯模型,即便于存储的最小信息
abstract class Node
{
public int BaseProperty { get; set; }
public NodeCollection Children { get; private set; } // : Collection<Node>
}
class NodeA /* NodeB, NodeC ... */ : Node
{
public int DerivedAProperty { get; set; }
}
,我需要将NodeX
类型的对象图转换为MyNodeX
类型的对象图,或者反之亦然,根本不改变任何NodeX
类,我发现自己经常使用这种模式:
NodeX->MyNodeX
// USAGE / external code
Node node = ...
MyNode myNode = MyNode.Load(node, ARGS); // static factory
// USAGE / external code
MyNode myNode = ...
Node node = myNode.Commit();
MyNodeX->NodeX
// USAGE / external code
Node node = ...
MyNode myNode = MyNode.Load(node, ARGS); // static factory
// USAGE / external code
MyNode myNode = ...
Node node = myNode.Commit();
我已经多次成功地使用了这种方法,我通常都很喜欢它,因为必须添加到类中的方法是直接的,外部代码也是如此。此外,它还通过调用base.Load(node)
/base.Commit(node)
来避免代码重复。然而,我真的不喜欢静态Load
factory方法中的if/else梯形图
对于Node->MyNode(Load
)情况,我希望在每种类型中都有一个工厂方法,类似于MyNode->Node(Commit
)情况。但是静态
和虚拟
显然有点问题。我也不想做我现在必须做的两个演员
实现这样一个目标是可能的吗?每件事的名称是否都像你上面提到的那样一致 如果是这样,您可以从使用反射的函数构建一组通用的convert-to-convert 以下是我的想法(这是意识流,不是经过验证的编译代码):
ConvertTo(TMy对象)
{
//创建类型为T的对象
T newObj=新的T();
//使用反射迭代T的成员
foreach(T中的成员)
{
//在TMy中查找“我的成员”对应项
//传输数据
}
返回newObj;
}
我将进一步研究这个问题,并可能在本周末的某个时候生成工作代码。我的建议是逐步解决这个问题。首先,您需要一些东西来遍历树并沿途转换每个节点:
public static class NodeExtensions
{
public static MyNode ToMy( this Node node )
{
var result = node.Transform();
result.Children = node.Children.Select( ToMy ).ToList();
}
public static Node FromMy( this MyNode node )
{
var result = node.Transform();
result.Children = node.Children.Select( ToMy ).ToList();
}
public static MyNode Transform( this Node node )
{
// TODO code to transform any single node here
}
public static Node Transform( this MyNode node )
{
// TODO code to transform any single node here
}
}
既然您提到从Node到MyNode的转换不是简单的复制属性的问题,但也表明会有很多这样的事情发生,我最初的想法是这是一项任务
AutoMapper允许您创建一个“转换配置文件”,描述要映射的属性以及要应用于任何给定映射的任何特殊规则。此外,它还提供泛型和非泛型方法,因此即使在编译时不知道类型,也可以使用它。它通常用于在实体和视图模型之间进行转换,因此您可以在此处的其他地方找到大量与它的用法相关的问题和答案
定义类型映射基本上由以下调用组成:
Mapper.CreateMap<Node,MyNode>(); // no special rules for this map
当一切就绪后,您可以通过以下方式转换整个树:
var myTree = node.ToMy();
// and back
node = myTree.FromMy();
使用允许遍历的数据结构,并使用访问者模式从一种类型转换为另一种类型(对不起,没有时间详细说明-食物!)…我不完全理解,你是想从NodeA转换到NodeB吗?@sircodesalot我正在尝试转换一个对象图,该对象图由
NodeA
,NodeB
等类型组成。。。对于由*My*NodeA
、*My*NodeB
等类型组成的对象图,反之亦然。不幸的是,在许多情况下,将MyT
的成员转换为T
中的等效成员或将其转换为T
中的等效成员并非易事。然而,更大的问题是我必须在方法调用中显式地指定T
。这意味着当我在foreach循环中转换子循环时,我必须使用类似的if-else梯形图来确定T
(除非你有一个解决方案)。从他们的文档的第一眼看,似乎我应该更早地使用AutoMapper。这个解决方案应该足够灵活,甚至可以处理复杂的属性,所以我将尝试一下。
public static MyNode Transform( this Node node )
{
return Mapper.Map( node.GetType(), node.GetMatchingMyType(), node );
}
public static Type GetMatchingType( this Node node )
{
// you can use a dictionary lookup or some other logic if this doesn't work
var typeName = "My" + node.GetType().Name;
return typeof(MyNode).Assembly.GetTypes().Single( t => t.Name == typeName );
}
var myTree = node.ToMy();
// and back
node = myTree.FromMy();