Примечание: пожалуйста, обратите внимание, что это не дубликат.
Мне нужно создать следующее лямбда-выражение:
() => model.property
модель и ее свойства будут определены во время выполнения. Мне нужна функция, которая принимает модель и свойство и генерирует выражение:
public object GenerateLambda(object model, string property)
{
}
Если это возможно, я не хочу, чтобы функция была общей.
но я думаю, что главная проблема, которая у меня есть, связана с выражением ()
.
Обновление: тип возвращаемого значения GenerateLambda
для меня сейчас не важен. Принимается любой результат, который можно заменить вместо ()=>model.property
. Причина, по которой я использовал объект, заключается в том, что я не знаю общих типов свойств, и они должны быть динамическими, но, как я тестировал, можно привести объект к Expression<Func<TValue?>>
, который является окончательным типом, который мне нужен (TValue
- это свойство тип, но он будет определен во время выполнения).
Я создал серию компонентов Blazor, у которых есть свойство (а именно For
) типа Expression<Func<TValue?>>
, которое используется для извлечения пользовательских атрибутов моделей. Я использую это свойство, устанавливая его в Func следующим образом: () => person.FirstName
. Теперь мне нужно динамически генерировать это выражение для каждого свойства объекта (модели). Предположим, что сам объект и его тип не создаются динамически.
Итак, для каждого свойства p в модели я хочу вызвать GenerateLambda(object model, string property)
, которое должно возвращать () => model.p
.
псевдокод:
foreach(propertyInfo p in model){
var result= GenerateLambda(model, p, X or any parameter that is needed);
MyComponent.For= result;
... // other logics
}
@IvanStoev Спасибо, я добавлю больше деталей
Хорошо, но теперь нам нужно дождаться, чтобы набрать достаточно голосов для повторного открытия.
@IvanStoev уже открыто!
Написание отражений и выражений динамически с высокой производительностью уже решено. Одним из примеров является эта замечательная библиотека с открытым исходным кодом, которая делает это и кэширует результаты в выражениях для максимальной производительности: https://github.com/ekonbenefits/dynamitey
Что-то вроде этого:
public static IEnumerable<Func<object>> GetGetters(object obj)
{
var type = obj.GetType();
var obj2 = Expression.Constant(obj);
foreach (var prop in type.GetProperties())
{
Expression prop2 = Expression.Property(obj2, prop);
// The boxing for value type is explicit,
// downcasting to reference type is implicit
if (prop2.Type.IsValueType)
{
prop2 = Expression.Convert(prop2, typeof(object));
}
var lambda = Expression.Lambda<Func<object>>(prop2);
var compiled = lambda.Compile();
yield return compiled;
}
}
Используйте так:
var model = new
{
Prop1 = 1,
Prop2 = new[] { 1, 2, 3 },
Prop3 = "Hello"
};
var test = GetGetters(model).ToArray();
Это первая версия кода... В лучшей версии создавались бы замыкания вокруг obj
и кешировались бы деревья выражений... Не уверен, что это действительно возможно. Ммм, нет... каррирование с деревьями выражений кажется невозможным. Создание метода, который возвращает другой метод, является большой проблемой для деревьев выражений. Вам нужно излучение Reflection.
Чтобы было ясно, оптимальным было бы иметь возможность генерировать это:
public static Func<object>[] MakeGetterProp1(MyClass obj)
{
Func<object> fn1 = () => obj.Prop1;
Func<object> fn2 = () => obj.Prop2;
return new[] { fn1, fn2 };
}
с помощью дерева выражений. Этот метод будет построен в первый раз и кэширован. Затем вы можете вызвать его и получить набор Fun<object>
, «замкнутых» вокруг определенного obj
. Не возможно я бы сказал.
Спасибо, все заработало без проблем. Хотя я удалил часть компиляции, само выражение выполнило свою работу.
Пожалуйста, предоставьте больше контекста для вопроса и уточните требования. Если вам нужно лямбда-выражение, то
object
не является правильным типом возвращаемого значения желаемой функцииpublic object GenerateLambda(object model, string property)
, должно бытьpublic LambdaExpression GenerateLambda(...)
? Также приведите пример, как он будет называться и для чего он будет использоваться.