至少有两种方法可以做到这一点:
1.Reflection和PropertyInfo
var obj = new TestClass();
var allProps = typeof(TestClass).GetProperties();
foreach (var prop in allProps)
{
// Get propertie value
object propValue = prop.GetGetMethod().Invoke(obj, null);
//Set propertie value
prop.GetSetMethod().Invoke(obj, new object[] { propValue });
}
您应该注意性能,只是对具有两个属性设置的类进行粗略测试,并且将所有属性获取 10k 次需要 0.06 秒(反射)和 0.001 秒(如果我手动编写)。所以对性能的影响是相当大的
2.动态方法
这种方法比较复杂,但性能非常值得。动态方法是程序在运行时为其发出 MSIL 的方法。它们由运行时执行,就好像它们是由编译器创建的一样(因此速度非常好)。使用此方法设置并在类上获取 2 个属性 10k 次需要 0.004 秒(相比之下,反射为 0.06 秒,手动为 0.001 秒)。 Bellow 是为特定类型的 getter 和 setter 生成委托数组的代码。生成动态可能会很昂贵,因此如果您打算多次使用(您可能会这样做),您应该缓存委托。
//Container for getters and setters of a property
public class MyProp
{
public string PropName { get; set; }
public Func<object,object> Getter{get;set;}
public Action<object,object> Setter{get;set;}
}
public static MyProp[] CreatePropertyDelagates (Type type)
{
var allProps = type.GetProperties();
var props = new MyProp[allProps.Length];
for(int i =0;i<allProps.Length;i++)
{
var prop = allProps[i];
// Getter dynamic method the signature would be :
// object Get(object thisReference)
// { return ((TestClass)thisReference).Prop; }
DynamicMethod dmGet = new DynamicMethod("Get", typeof(object), new Type[] { typeof(object), });
ILGenerator ilGet = dmGet.GetILGenerator();
// Load first argument to the stack
ilGet.Emit(OpCodes.Ldarg_0);
// Cast the object on the stack to the apropriate type
ilGet.Emit(OpCodes.Castclass, type);
// Call the getter method passing the object on the stack as the this reference
ilGet.Emit(OpCodes.Callvirt, prop.GetGetMethod());
// If the property type is a value type (int/DateTime/..) box the value so we can return it
if (prop.PropertyType.IsValueType)
{
ilGet.Emit(OpCodes.Box, prop.PropertyType);
}
// Return from the method
ilGet.Emit(OpCodes.Ret);
// Setter dynamic method the signature would be :
// object Set(object thisReference, object propValue)
// { return ((TestClass)thisReference).Prop = (PropType)propValue; }
DynamicMethod dmSet = new DynamicMethod("Set", typeof(void), new Type[] { typeof(object), typeof(object) });
ILGenerator ilSet = dmSet.GetILGenerator();
// Load first argument to the stack and cast it
ilSet.Emit(OpCodes.Ldarg_0);
ilSet.Emit(OpCodes.Castclass, type);
// Load secons argument to the stack and cast it or unbox it
ilSet.Emit(OpCodes.Ldarg_1);
if (prop.PropertyType.IsValueType)
{
ilSet.Emit(OpCodes.Unbox_Any,prop.PropertyType);
}
else
{
ilSet.Emit(OpCodes.Castclass, prop.PropertyType);
}
// Call Setter method and return
ilSet.Emit(OpCodes.Callvirt, prop.GetSetMethod());
ilSet.Emit(OpCodes.Ret);
// Create the delegates for invoking the dynamic methods and add the to an array for later use
props[i] = new MyProp()
{
PropName = prop.Name,
Setter = (Action<object, object>)dmSet.CreateDelegate(typeof(Action<object, object>)),
Getter = (Func<object, object>)dmGet.CreateDelegate(typeof(Func<object, object>)),
};
}
return props;
}
动态方法的调用:
// Should be cahced for further use
var testClassProps = CreatePropertyDelagates(typeof(TestClass));
var obj = new TestClass();
foreach (var p in testClassProps)
{
var propValue = p.Getter(obj);
p.Setter(obj,propValue);
}
Obs:上面的代码不处理没有 getter 或没有 setter 或标记为私有的属性。这可以通过查看 ProperyInfo 类的属性并仅在适当的情况下创建委托来轻松完成