Cœu*_*œur 5 c# inheritance constructor clone base-class
我有一个Item和一个子类AdvancedItem(如果重要的话,所有都由值类型组成):
public Item
{
public string A;
public bool B;
public char C;
...// 20 fields
}
public AdvancedItem : Item
{
public string Z;
}
Run Code Online (Sandbox Code Playgroud)
单独创建Item或AdvancedItem很容易:
var item = new Item { A = "aa", B = true, C = 'c', ... };
var aItem = new AdvancedItem { A = "aa", B = true, C = 'c', ..., Z = "zz" };
Run Code Online (Sandbox Code Playgroud)
现在,我只想通过分别提供字符串Z将Item转换为AdvancedItem.为了实现这一点,我正在考虑使用构造函数.
尝试A:
// annoying, we are not using the inheritance of AdvancedItem:Item
// so we will need to edit this whenever we change the class Item
public AdvancedItem(Item item, string z)
{
A = item.A;
B = item.B;
...;//many lines
Z = z;
}
Run Code Online (Sandbox Code Playgroud)
尝试B:
// to use inheritance it seems I need another constructor to duplicate itself
public Item(Item item)
{
A = item.A;
B = item.B;
...;//many lines
}
public AdvancedItem(Item item, string z) : base(Item)
{
Z = z;
}
Run Code Online (Sandbox Code Playgroud)
有没有办法改进第二次尝试,以避免写多行X = item.X?也许是一个自动克隆或自动复制一个类的解决方案,public Item(Item item)它将在一行中写入?
考虑使用AutoMapper复制对象之间的属性.
这将允许以下内容:
Item a = new Item { A = 3, B = 'a', .... };
AdvancedItem advanced= Mapper.Map<AdvancedItem>(a);
string z = "Hello World";
advanced.Z = z;
Run Code Online (Sandbox Code Playgroud)
更新
如果你不想使用AutoMapper你可以使用Reflection或更好,Expressions.但是,这会使您的代码更复杂一些
考虑以下两种类型:
class Item
{
public int A, B, C;
public string D, E, F;
private int privateInt;
public Item(int valueOfPrivateField)
{
privateInt = valueOfPrivateField;
}
}
class AdvancedItem : Item
{
public string G;
public AdvancedItem(int valueOfPrivateField) : base(valueOfPrivateField)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以定义一个创建字段副本表达式的方法.既然你提到你的所有字段都是值类型,我们可以将每个字段逐个复制到另一个对象:
private static void MapFields<T>(T target, T source)
{
Type type = typeof (T);
if (!Mappers.ContainsKey(type))
{
//build expression to copy fields from source to target;
var targetParam = Expression.Parameter(typeof(object));
var targetCasted = Expression.TypeAs(targetParam, typeof(T));
var sourceParam = Expression.Parameter(typeof(object));
var sourceCasted = Expression.TypeAs(sourceParam, typeof(T));
var setters = new List<Expression>();
//get all non-readonly fields
foreach (var fieldInfo in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(f => !f.IsInitOnly))
{
Expression targetField = Expression.Field(targetCasted, fieldInfo);
Expression sourceField = Expression.Field(sourceCasted, fieldInfo);
setters.Add(Expression.Assign(targetField, sourceField));
}
Expression block = Expression.Block(setters);
var mapperFunction = Expression.Lambda<Action<object, object>>(block, targetParam,
sourceParam).Compile();
Mappers[type] = mapperFunction;
}
Mappers[type](target, source);
}
private static readonly Dictionary<Type, Action<object, object>> Mappers =
new Dictionary<Type, Action<object, object>>();
Run Code Online (Sandbox Code Playgroud)
这会缓存从源到目标对象映射所有字段的函数,并且应该具有与手动编写this.A = A, this.B = B等相同的性能.
调用方法:
static void Main(string[] args)
{
var item = new Item(56) {A = 5, B = 6};
var advanced = new AdvancedItem(0);
MapFields(advanced, item);
int a = advanced.A; //5
int b = advanced.B; //6;
//note that advanced.privateInt == 56!
}
Run Code Online (Sandbox Code Playgroud)
请注意,此代码比AutoMapper更复杂且更不可靠,不建议或准备好用于生产系统.