给定一个包含 35 个字段的类和 2 个具有一定数量不同字段值的对象。
有没有一种聪明的方法来获得一个 list
例如
obj1.Name = "aaa";
obj1.LastName = "bbb";
obj1.Address = "xcs";
obj2.Name = "aaa";
obj2.LastName = "ccc";
obj2.Address = "jk";
目标:
list<<String>String> containing 2 Strings LastName and Address
我认为反射是可行的方法,但我担心 35 个字段太重了。 还有其他想法吗,比如 linq?
最佳答案
好的;这比我通常要付出的努力多疯狂,但这可能是一种有用的实用方法。它动态创建 IL(缓存)来完成工作,处理值类型对象与引用类型对象、内置 IL 相等性、相等运算符(==
)和EqualityComparer<T>
。其余的:
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApplication2
{
using System;
class Program
{
static void Main()
{
WriteDeltas(new Foo {X = 123, Y = DateTime.Today, Z = null},
new Foo {X = 124, Y = DateTime.Today, Z = null});
WriteDeltas(new Foo { X = 123, Y = DateTime.Today, Z = null },
new Foo { X = 123, Y = DateTime.Now, Z = new Dummy()});
WriteDeltas(new Bar { X = 123, Y = DateTime.Today, Z = null },
new Bar { X = 124, Y = DateTime.Today, Z = null });
WriteDeltas(new Bar { X = 123, Y = DateTime.Today, Z = null },
new Bar { X = 123, Y = DateTime.Now, Z = new Dummy() });
}
static void WriteDeltas<T>(T x, T y)
{
Console.WriteLine("----");
foreach(string delta in PropertyComparer<T>.GetDeltas(x,y))
{
Console.WriteLine(delta);
}
}
}
class Dummy {}
class Foo
{
public int X { get; set; }
public DateTime Y { get; set; }
public Dummy Z { get; set; }
}
struct Bar
{
public int X { get; set; }
public DateTime Y { get; set; }
public Dummy Z { get; set; }
}
public static class PropertyComparer<T>
{
private static readonly Func<T, T, List<string>> getDeltas;
static PropertyComparer()
{
var dyn = new DynamicMethod(":getDeltas", typeof (List<string>), new[] {typeof (T), typeof (T)},typeof(T));
var il = dyn.GetILGenerator();
il.Emit(OpCodes.Newobj, typeof (List<string>).GetConstructor(Type.EmptyTypes));
bool isValueType = typeof (T).IsValueType;
OpCode callType = isValueType ? OpCodes.Call : OpCodes.Callvirt;
var add = typeof(List<string>).GetMethod("Add");
foreach (var prop in typeof(T).GetProperties())
{
if (!prop.CanRead) continue;
Label next = il.DefineLabel();
switch (Type.GetTypeCode(prop.PropertyType))
{
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.Char:
case TypeCode.Double:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.SByte:
case TypeCode.Single:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
if(isValueType) {il.Emit(OpCodes.Ldarga_S, (byte)0);} else {il.Emit(OpCodes.Ldarg_0);}
il.EmitCall(callType, prop.GetGetMethod(), null);
if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); }
il.EmitCall(callType, prop.GetGetMethod(), null);
il.Emit(OpCodes.Ceq);
break;
default:
var pp = new Type[] {prop.PropertyType, prop.PropertyType};
var eq = prop.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static, null, pp, null);
if (eq != null)
{
if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)0); } else { il.Emit(OpCodes.Ldarg_0); }
il.EmitCall(callType, prop.GetGetMethod(), null);
if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); }
il.EmitCall(callType, prop.GetGetMethod(), null);
il.EmitCall(OpCodes.Call, eq, null);
}
else
{
il.EmitCall(OpCodes.Call, typeof(EqualityComparer<>).MakeGenericType(prop.PropertyType).GetProperty("Default").GetGetMethod(), null);
if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)0); } else { il.Emit(OpCodes.Ldarg_0); }
il.EmitCall(callType, prop.GetGetMethod(), null);
if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); }
il.EmitCall(callType, prop.GetGetMethod(), null);
il.EmitCall(OpCodes.Callvirt, typeof(EqualityComparer<>).MakeGenericType(prop.PropertyType).GetMethod("Equals", pp), null);
}
break;
}
il.Emit(OpCodes.Brtrue_S, next); // equal
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldstr, prop.Name);
il.EmitCall(OpCodes.Callvirt, add, null);
il.MarkLabel(next);
}
il.Emit(OpCodes.Ret);
getDeltas = (Func<T, T, List<string>>)dyn.CreateDelegate(typeof (Func<T, T, List<string>>));
}
public static List<string> GetDeltas(T x, T y) { return getDeltas(x, y); }
}
}
关于c# - 比较 2 个对象并检索具有不同值的字段列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3060382/