C# 比较两个对象并检索具有不同值的字段列表
给定一个包含35个字段和2个具有一定数量不同字段值的对象的类。 有没有一种聪明的方法可以获得一个包含字段名的列表,其中的对象如下所示 e、 g 目标:C# 比较两个对象并检索具有不同值的字段列表,c#,linq,C#,Linq,给定一个包含35个字段和2个具有一定数量不同字段值的对象的类。 有没有一种聪明的方法可以获得一个包含字段名的列表,其中的对象如下所示 e、 g 目标: list<<String>String> containing 2 Strings LastName and Address 包含两个字符串LastName和Address的列表 我认为倒影是一种方式,但对于35个领域,我担心它太重了。 任何其他的想法,比如linq?反射就是解决这个问题的方法,我不认为35个字段是一个
list<<String>String> containing 2 Strings LastName and Address
包含两个字符串LastName和Address的列表
我认为倒影是一种方式,但对于35个领域,我担心它太重了。
任何其他的想法,比如linq?反射就是解决这个问题的方法,我不认为35个字段是一个问题 (完全弄糊涂了之后,我想我理解这个问题,反思一下就可以了)。好;这比我通常要付出的努力多得多,但这可能是一种有用的实用方法。它动态创建IL(缓存)来完成工作,处理值类型与引用类型对象、内置IL相等、相等运算符(
==
),其余部分使用EqualityComparer
:
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); }
}
}
使用System.Collections.Generic;
运用系统反思;
使用System.Reflection.Emit;
命名空间控制台应用程序2
{
使用制度;
班级计划
{
静态void Main()
{
WriteDeltas(新的Foo{X=123,Y=DateTime.Today,Z=null},
新Foo{X=124,Y=DateTime.Today,Z=null});
WriteDeltas(新的Foo{X=123,Y=DateTime.Today,Z=null},
新Foo{X=123,Y=DateTime.Now,Z=newdummy()});
WriteDelta(新条{X=123,Y=DateTime.Today,Z=null},
新条{X=124,Y=DateTime.Today,Z=null});
WriteDelta(新条{X=123,Y=DateTime.Today,Z=null},
新条{X=123,Y=DateTime.Now,Z=newdummy()});
}
静态void writedelta(tx,ty)
{
控制台写入线(“---”);
foreach(PropertyComparer.getDelta(x,y)中的字符串增量)
{
控制台写入线(增量);
}
}
}
类虚拟{}
福班
{
公共整数X{get;set;}
公共日期时间Y{get;set;}
公共伪Z{get;set;}
}
结构条
{
公共整数X{get;set;}
公共日期时间Y{get;set;}
公共伪Z{get;set;}
}
公共静态类属性比较程序
{
私有静态只读函数getDelta;
静态属性比较程序()
{
var dyn=newdynamicmethod(“:getDelta”,typeof(List),new[]{typeof(T),typeof(T)},typeof(T));
var il=dyn.GetILGenerator();
Emit(opcode.Newobj,typeof(List).GetConstructor(Type.EmptyTypes));
bool isValueType=typeof(T)。isValueType;
OpCode callType=isValueType?OpCode.Call:OpCode.Callvirt;
var add=typeof(List).GetMethod(“add”);
foreach(typeof(T).GetProperties()中的var prop)
{
如果(!prop.CanRead)继续;
Label next=il.DefineLabel();
开关(Type.GetTypeCode(prop.PropertyType))
{
大小写类型代码。布尔值:
大小写类型代码。字节:
case TypeCode.Char:
案例类型代码。双:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
案例类型代码.SByte:
案例类型代码。单个:
案例类型代码.UInt16:
案例类型代码.UInt32:
案例类型代码.UInt64:
if(isValueType){il.Emit(OpCodes.Ldarga_S,(byte)0);}else{il.Emit(OpCodes.Ldarg_0);}
EmitCall(callType,prop.getMethod(),null);
if(isValueType){il.Emit(opcode.Ldarga_S,(byte)1);}else{il.Emit(opcode.Ldarg_1);}
EmitCall(callType,prop.getMethod(),null);
发射(操作码Ceq);
打破
违约:
var pp=新类型[]{prop.PropertyType,prop.PropertyType};
var eq=prop.PropertyType.GetMethod(“op_Equality”,BindingFlags.Public | BindingFlags.Static,null,pp,null);
如果(等式!=null)
{
if(isValueType){il.Emit(OpCodes.Ldarga_S,(byte)0);}else{il.Emit(OpCodes.Ldarg_0);}
EmitCall(callType,prop.getMethod(),null);
if(isValueType){il.Emit(opcode.Ldarga_S,(byte)1);}else{il.Emit(opcode.Ldarg_1);}
EmitCall(callType,prop.getMethod(),null);
il.EmitCall(操作码.Call,eq,null);
}
其他的
{
EmitCall(OpCodes.Call,typeof(EqualityComparer).MakeGenericType(prop.PropertyType).GetProperty(“默认”).getMethod(),null);
if(isValueType){il.Emit(OpCodes.Ldarga_S,(byte)0);}else{il.Emit(OpCodes.Ldarg_0);}
EmitCall(callType,prop.getMethod(),null);
if(isValueType){il.Emit(opcode.Ldarga_S,(byte)1);}else{il.Emit(opcode.Ldarg_1);}
EmitCall(callType,prop.getMethod(),null);
EmitCall(OpCodes.Callvirt,typeof(EqualityComparer).MakeGenericType(prop.PropertyType).GetMethod(“Equals”,pp),null);
}
打破
}
il.Emit(OpCodes.Brtrue_S,next);//相等
发射(操作码Dup);
il.Emit(opcode.Ldstr,prop.Name);
EmitCall(OpCodes.Callvirt,add,null);
il.MarkLabel(下一页)
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); }
}
}