3
votes

I am trying to serialize something based upon meeting particular criteria.

To this end my original hope was to use attributes containing a lambda expression on an object's properties.

However, as this cannot be done I've settled for having a Func<T,bool> member within the class and passing the type (or first parameter type) and name of this Func through the property attribute. E.g.:

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

In my serializer I need to call this Func<T, bool>.

Let's assume I have a Type t which is equal to typeof(SomeObject) in this case, or more abstractly, typeof(T). I can also get the Func<T,bool> itself, but only through reflection as an object.

My naive approach is something along these lines:

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 */

But this leads to the problem of casting a lambda to a delegate which is apparently erroneous.

I tried this in place of 'func':

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

But that relies on func being a method call not a lambda.

So, can anyone point me in the right direction?

3

3 Answers

4
votes

You can just do something like this, without need for expressions:

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

and to get the value:

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

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

edit to get the value without knowing the type:

bool validates = (bool)((Delegate)a.GetValue(null)).DynamicInvoke(100);
1
votes

I think you can use Compile method of a lambda expression to cast it to a delegate.

here's what I found on MSDN:

The Expression<(Of <(TDelegate>)>) type provides the Compile method, that compiles the code represented by the expression tree into an executable delegate. This executable code is equivalent to the executable code that would have been generated had the lambda expression been assigned to a delegate type originally.

Here you can find it.

1
votes

Not sure this is working sample, but this is the way:

// 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);

now you can call the "func" method like this:

Boolean result = lambda.Compile()(SomeObjectInstance);