views:

310

answers:

3

Hi,

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?

+1  A: 

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.

Beatles1692
Yes thanks, but I need an Expression to be able to Compile it. As it is I cannot create the Expression.
Graphain
Ah but I see an example there where I can simply go Expression<Func<SomeObject, bool>> = (lambda) in place of (Func<SomeObject, bool>>>). I'll just make sure to reference Expressions rather than Funcs in my object classes. Pity I can't find a way to convert the two dynamically.
Graphain
isn't Func<T,T> a delegate ? why you want to convert it to a lambda expression ?
Beatles1692
If there's a better way to get the result of evaluating the Func, bearing in mind that it is of type object, I'd love to know it.
Graphain
+3  A: 

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);
Jan Jongboom
I have a type variable, not the actual type and you can't go (Predicate<sometypevariable>)a.GetValue(). Can you still take this approach?
Graphain
Yes, see my edit, with the cast to delegate and the DynamicInvoke.
Jan Jongboom
Great! Thank you :-). Looks simplest solution and testing now.
Graphain
+1  A: 

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);
Kamarey
Hmm it looks like it might work, but bear in mind I don't know SomeObject, I just have a type variable representing it. So I can't on the last line go Expression.Lambda<Func<SomeObject, Boolean>>. But the non generic Lambda method may be able to help me.
Graphain
I was also trying to avoid creating a full method wrapping the Func as the original problem is about decorating existing properties as easily as possible.
Graphain