Динамически получить результат вызова Func <T, bool> - PullRequest
2 голосов
/ 14 сентября 2009

Я пытаюсь сериализовать что-то на основе соответствия определенным критериям.

С этой целью моей первоначальной надеждой было использование атрибутов, содержащих лямбда-выражения в свойствах объекта.

Тем не менее, поскольку это не может быть сделано, я согласился на наличие в классе члена Func и передачу типа (или первого типа параметра) и имени этого Func через атрибут свойства. E.g.:

Func<SomeObject, bool> func = (p => p.Value == 4);
[FuncAtt(typeof(SomeObject), "func")]
public SomeObject PropertyName { get; set;}

В моем сериализаторе мне нужно вызвать этот Func .

Давайте предположим, что у меня есть Type t, который равен typeof (SomeObject) в этом случае, или, более абстрактно, typeof (T). Я также могу получить Func , но только через отражение как объект.

Мой наивный подход такой:

object func = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
Type funcType = typeof(Func<,>).MakeGenericType(attribute.Type, typeof(bool));

ParameterExpression p = Expression.Parameter(attribute.Type, objectToSerialize);
LambdaExpression l = Expression.Lambda(funcType, func, p); /* Won't work */

Но это приводит к проблеме приведения лямбды к делегату, которая, по-видимому, ошибочна.

Я попробовал это вместо 'func':

(Expression)((Action)(() => func))

Но это зависит от того, что func - это вызов метода, а не лямбда.

Итак, кто-нибудь может указать мне правильное направление?

Ответы [ 3 ]

4 голосов
/ 14 сентября 2009

Вы можете просто сделать что-то вроде этого, без необходимости выражений:

public static class Test
{
    public static Predicate<int> func = s => s > 20;
}

и для получения значения:

    private void Form1_Load(object sender, EventArgs e)
    {
        var a = typeof(Test).GetField("func");

        bool validates = ((Predicate<int>)a.GetValue(null)).Invoke(100);
    }

изменить чтобы получить значение, не зная типа:

bool validates = (bool)((Delegate)a.GetValue(null)).DynamicInvoke(100);
1 голос
/ 14 сентября 2009

Не уверен, что это рабочий образец, но это так:

// not sure what are you doing in this line, but assume it should return
// a method name specified in the attribute, e.g. "func" in your example.
// Also "func" must be a method (static one in my example) of SomeObject class
String funcname = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
ParameterExpression param = Expression.Parameter(typeof(SomeObject), "p");
MethodCallExpression call = Expression.Call(SomeObject, funcname, new Type[] { typeof(SomeObject), typeof(Boolean) }, param);
LambdaExpression lambda = Expression.Lambda<Func<SomeObject, Boolean>>(call, param);

теперь вы можете вызывать метод "func" следующим образом:

Boolean result = lambda.Compile()(SomeObjectInstance);
1 голос
/ 14 сентября 2009

Я думаю, вы можете использовать метод компиляции лямбда-выражения, чтобы привести его к делегату.

вот что я нашел на MSDN:

Выражение <(Of <(TDelegate>)>) тип предоставляет метод Compile, который компилирует код, представленный дерево выражений в исполняемый файл делегировать. Этот исполняемый код эквивалентно исполняемому коду, который был бы создан, если бы лямбда-выражение было присвоено тип делегата изначально.

Здесь вы можете найти его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...