我有两个这样的对象:
object obj1=new
{
ID=1,
Title="text",
Test= new Test(){
Number=20, IsSomething=false
}
}
object obj2=new
{
Age=22
}
我想像这样以编程方式将它们合并:
object obj3=new
{
ID=1,
Title="text",
Test= new Test(){
Number=20, IsSomething=false
},
Age=22
}
请注意,可能可以启动每个类而不是Test类,并且我不知道对象中具有哪个类,而我只是在运行时才找到这些对象。
我在StackOverflow中阅读了相同的问题,发现我应该使用Reflection,但是他们所有人都知道类的类型,而我只是在运行时才发现它。 怎么可能?
答案 0 :(得分:4)
static class MergeExtension
{
public static ExpandoObject Merge<TLeft, TRight>(this TLeft left, TRight right)
{
var expando = new ExpandoObject();
IDictionary<string, object> dict = expando;
foreach (var p in typeof(TLeft).GetProperties())
dict[p.Name] = p.GetValue(left);
foreach (var p in typeof(TRight).GetProperties())
dict[p.Name] = p.GetValue(right);
return expando;
}
}
用法
var obj1 = new
{
ID = 1,
Title = "text",
Test = new Test()
{
Number = 20,
IsSomething = false
}
};
var obj2 = new
{
Age = 22
};
dynamic obj3 = obj1.Merge(obj2);
Console.WriteLine(obj1.ID.Equals(obj3.ID)); // True
Console.WriteLine(obj1.Title.Equals(obj3.Title)); // True
Console.WriteLine(obj1.Test.Equals(obj3.Test)); // True
Console.WriteLine(obj2.Age.Equals(obj3.Age)); // True
注意,如果类型具有相同的属性名称,则需要某种机制来解决属性冲突。
答案 1 :(得分:1)
基于以下答案:https://stackoverflow.com/a/3862241/9748260
我对提供的类型生成器进行了一些修改,如下所示:
public static class MyTypeBuilder
{
public static Type CompileResultType(List<PropertyInfo> yourListOfFields, string typeName)
{
TypeBuilder tb = GetTypeBuilder(typeName);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
// NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
foreach (var field in yourListOfFields)
CreateProperty(tb, field.Name, field.PropertyType);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder(string typeSignature)
{
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
然后我创建了一种合并对象的方法:
public static object Merge(object obj1, object obj2, string newTypeName)
{
var obj1Properties = obj1.GetType().GetProperties();
var obj2Properties = obj2.GetType().GetProperties();
var properties = obj1Properties.Concat(obj2Properties).ToList();
Type mergedType = MyTypeBuilder.CompileResultType(properties, newTypeName);
object mergedObject = Activator.CreateInstance(mergedType);
var mergedObjectProperties = obj2.GetType().GetProperties();
foreach(var property in obj1Properties)
{
mergedObject.GetType().GetProperty(property.Name).SetValue(mergedObject, obj1.GetType().GetProperty(property.Name).GetValue(obj1, null) , null);
}
foreach(var property in obj2Properties)
{
mergedObject.GetType().GetProperty(property.Name).SetValue(mergedObject, obj2.GetType().GetProperty(property.Name).GetValue(obj2, null) , null);
}
return mergedObject;
}
要测试结果:
object obj1 = new
{
ID = 1,
Title = "text",
Test = new
{
Number = 20,
IsSomething = false
}
};
object obj2 = new
{
Age = 22
};
object merged = Merge(obj1, obj2, "merged");
foreach(var x in merged.GetType().GetProperties())
{
Console.WriteLine($"{x.Name} = {x.GetValue(merged, null)}");
}
Console.ReadLine();
输出为:
ID = 1
Title = text
Test = { Number = 20, IsSomething = False }
Age = 22
为简要说明这一点,其想法是创建一个同时具有两个对象的属性的新对象并复制其值。