Есть как минимум два способа сделать это:
1. Отражение и информация о недвижимости
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 });
}
Вы должны быть осторожны с производительностью, хотя грубый тест для класса с установкой двух свойств и получением всех свойств 10 000 раз занимает 0,06 секунды с отражением и 0,001 секунды, если я пишу это от руки. Таким образом, хит производительности довольно резкий
2.Динамические методы
Этот метод более сложный, но производительность того стоит. Динамические методы - это методы, для которых программа генерирует MSIL во время выполнения. Они выполняются во время выполнения, как если бы они были созданы компилятором (поэтому скорость очень хорошая). При использовании этого метода установка и получение 2 свойств в классе 10 000 раз заняла 0,004 секунды (по сравнению с 0,06 секундами с отражением и 0,001 секунды вручную). Ниже приведен код для генерации массива делегатов для методов получения и установки для определенного типа. Генерация динамики может быть дорогостоящей, поэтому вы должны кэшировать делегатов, если вы собираетесь использовать несколько раз (что вы, вероятно, будете).
//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 или setterter или помечены как частные. Это можно легко сделать, взглянув на свойства класса ProperyInfo и создавая делегатов только в случае необходимости