Я использую следующий код для кэширования свойство геттер/сеттер делегатов для быстрого доступа к этой функциональности:Использование выражений для доступа к свойствам структуры в C#
class PropertyHelper
{
public static Func<object, object> BuildGetter(PropertyInfo propertyInfo)
{
var method = propertyInfo.GetGetMethod(true);
var obj = Expression.Parameter(typeof(object), "o");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);
return expr.Compile();
}
public static Action<object, object> BuildSetter(PropertyInfo propertyInfo)
{
var method = propertyInfo.GetSetMethod(true);
var obj = Expression.Parameter(typeof(object), "o");
var value = Expression.Parameter(typeof(object));
Expression<Action<object, object>> expr =
Expression.Lambda<Action<object, object>>(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method,
Expression.Convert(value, method.GetParameters()[0].ParameterType)),
obj,
value);
Action<object, object> action = expr.Compile();
return action;
}
}
Это работает очень хорошо, когда доступ к свойствам объектов класса , но он терпит неудачу, когда я использую его для объекта struct. Например, рассмотрим следующий код:
public struct LocationStruct
{
public double X { get; set; }
public double Y { get; set; }
}
public class LocationClass
{
public double X { get; set; }
public double Y { get; set; }
}
public class Tester
{
public static void TestSetX()
{
Type locationClassType = typeof(LocationClass);
PropertyInfo xProperty = locationClassType.GetProperty("X");
Action<object, object> setter = PropertyHelper.BuildSetter(xProperty);
LocationStruct testLocationClass = new LocationClass();
setter(testLocationClass, 10.0);
if (testLocationClass.X == 10.0)
{
MessageBox.Show("Worked for the class!");
}
Type locationStructType = typeof(LocationStruct);
xProperty = locationStructType.GetProperty("X");
setter = PropertyHelper.BuildSetter(xProperty);
LocationStruct testLocationStruct = new LocationStruct();
setter(testLocationStruct, 10.0);
if (testLocationStruct.X != 10.0)
{
MessageBox.Show("Didn't work for the struct!");
}
}
}
Первая часть работы, устанавливая значение Х testLocationClass до 10. Однако, поскольку LocationStruct является структурой, то testLocationStruct передается по значению, то значение (внутренний для метод, вызываемый делегатом) get имеет свой X, установленный в 10, но объект testLocationStruct в вышеуказанном блоке кода остается неизменным.
Итак, мне нужна методология доступа к свойствам структурных объектов, аналогичных приведенным выше (что работает только для свойств объектов класса). Я попытался выполнить это, используя шаблоны «пройти по ссылке», но я просто не могу заставить его работать.
Может ли кто-нибудь предоставить аналогичные методы BuildGetter и BuildSetter, которые могут использоваться для кэширования делегатов getter/setter для значений свойств struct?
Краткое примечание: Это не называется лямбда-выражения, только выражения или деревья выражений. Lambdas больше ссылается на замыкания, то есть анонимные функции на C#. – metacubed
Rgr ... thx для заметки. Я изменю свой заголовок и тег. – FTLPhysicsGuy
Просьба уточнить, что об этом не работает для типов значений (structs). Вы сталкиваетесь с проблемой обработки типов значений в штучной упаковке? Если да, можно ли это решить, изменив свой код, чтобы он был общим, а не предполагал System.Object?Вы должны опубликовать код, который демонстрирует использование вашей реализации для типов значений, четко показывая, как это не работает для вас. –