如果我有课:
class NodeA
{
public string Name{get;set;}
public List<NodeA> Children {get;set;}
// etc some other properties
}
还有其他一些课程:
class NodeB
{
public string Name;
public IEnumerable<NodeB> Children;
// etc some other fields;
}
如果我需要将 NodeB 对象转换为 NodeA 类型,最好的方法是什么?创建一个包装类?如果我必须创建一个包装类,如何创建它以便所有 wpf 控件仍然能够成功绑定到属性?
我需要创建这样的演员阵容的原因:
有一个程序使用了一种旧算法,该算法在编译的程序中返回符号列表(IMemorySymbol)。我们已经工作并创建了一种新算法,并且字段和属性有所不同(ISymbolElem)。我们需要执行临时转换,以便在 wpf 应用程序的视图中显示属性。
一对夫妇走近...
复制构造函数
有一个 NodeA 和 NodeB 包含一个采用相反的构造函数:
class NodeA
{
public string Name{get;set;}
public List<NodeA> Children {get;set;}
// COPY CTOR
public NodeA(NodeB copy)
{
this.Name = copy.Name;
this.Children = new List<NodeA>(copy.Children.Select(b => new NodeA(b));
//copy other props
}
}
显式或隐式运算符
显式你会像
NodeA a = (NodeA)b;
一样进行转换,而隐式你可以跳过括号。
public static explicit operator NodeA(NodeB b)
{
//if copy ctor is defined you can call one from the other, else
NodeA a = new NodeA();
a.Name = b.Name;
a.Children = new List<NodeA>();
foreach (NodeB child in b.Children)
{
a.Children.Add((NodeA)child);
}
}
如果您不关心将
NodeA
的实现耦合到 NodeB
,则添加复制构造函数,如下所示:
class NodeA
{
public NodeA() { }
public NodeA(NodeB node)
{
Name = node.Name;
Children = node.Children.Select(n => new NodeA(n)).ToList();
}
public string Name{get;set;}
public List<NodeA> Children {get;set;}
// etc some other properties
}
Convert
样式的类来为您进行转换。 请注意,Automapper 框架通过使用源类型和目标类型的反射为您生成这些类型的转换。
从通用接口继承怎么样?
interface INode {
public string Name{get;set;}
public IEnumerable<INode> Children {get;set;}
}
class NodeA : INode {
public string Name{get;set;}
public List<NodeA> Children {get;set;}
// etc some other properties
}
class NodeB : INode {
public string Name;
public IEnumerable<NodeB> Children;
// etc some other fields;
}
void myMethod() {
INode nodeB = new NodeB();
INode nodeA = nodeB;
}
我最近编写了一个通用方法来执行此操作,该方法应该适用于任何形式的嵌套树映射:
/// <summary>
/// Remap the full tree to a new tree
/// </summary>
/// <typeparam name="TSource">Source type</typeparam>
/// <typeparam name="TOut">Result type</typeparam>
/// <param name="source">Source tree</param>
/// <param name="selector">Source type map to <typeparamref name="TOut"/></param>
/// <param name="childrenSelector">Children of source selector</param>
/// <param name="outChildrenSetter">Set children to result type</param>
public static IEnumerable<TOut> MapTree<TSource, TOut>(this IEnumerable<TSource> source,
Func<TSource, TOut> selector, Func<TSource, IEnumerable<TSource>?> childrenSelector,
Action<TOut, IEnumerable<TOut>?> outChildrenSetter)
{
return source.Select(InnerSelector);
TOut InnerSelector(TSource s)
{
var outData = selector(s);
outChildrenSetter(outData, childrenSelector(s)?.Select(InnerSelector));
return outData;
}
}
示例:
treeNodeB.MapTree<NodeB, NodeA>(b => b.Children,
(b, aChildren) => new NodeA()
{
Name = b.Name,
Children = aChildren?.ToList()
}).ToList();