Create Expression from Func? (3.5 SP1)

J

Jehu Galeahsa

Hello:

Is there are way to create an Expression from a Func? I don't like
cluttering up my method signatures with the whole
Expression<Func<TResult, T>> type. I would prefer for callers to
simply see Func<TResult, T> instead.

I'd like to take a Func and create an Expression from it. Is that
possible?

Thanks,
Travis Parks
 
P

Peter Duniho

Jehu said:
Hello:

Is there are way to create an Expression from a Func? I don't like
cluttering up my method signatures with the whole
Expression<Func<TResult, T>> type. I would prefer for callers to
simply see Func<TResult, T> instead.

I'd like to take a Func and create an Expression from it. Is that
possible?

Probably. But it's hard to know for sure what you're asking.

The delegate type Func<TResult, T> is just like any other delegate type,
and has both a target method (System.Reflection.MethodInfo) and (for
instance methods) a target instance (System.Object). You can retrieve
these from the delegate instance in question.

With those objects in hand, you can create an Expression instance that
accomplishes the same thing.

Pete
 
J

Jehu Galeahsa

Probably.  But it's hard to know for sure what you're asking.

I'm asking whether you can create an Expression from a Func. I don't
want the signature of my method to show Expresion<...> I want it to
show the Func<...>. I would then have to manufacture the
Expression said:
The delegate type Func<TResult, T> is just like any other delegate type,
and has both a target method (System.Reflection.MethodInfo) and (for
instance methods) a target instance (System.Object).  You can retrieve
these from the delegate instance in question.

With those objects in hand, you can create an Expression instance that
accomplishes the same thing.

Could you show me this? Now, remember, it is important that the
generated Expression<...> provide the same information that I would
get from the parameter. In my scenario, I am using Expression trees to
grab properties, to avoid using string literals of the property names.
This way refactoring correctly changes my code to use the correct
property.

Say I had a method like this:

private static string
getProperty<TValue>(Expression<Func<TDataObject, TValue>>
propertyChooser)
{
if (propertyChooser == null)
{
throw new ArgumentNullException("propertyChooser",
"The property chooser must not be null.");
}
MemberExpression memberExpression = propertyChooser.Body
as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("The property chooser did
not resolve to a property.", "propertyChooser");
}
PropertyInfo property = memberExpression.Member as
PropertyInfo;
if (property == null)
{
throw new ArgumentException("The property chooser did
not resolve to a property.", "propertyChooser");
}
return property.Name;
}

You call it like this:

string propertyName = getProperty(a => a.MyProperty); // should return
'MyProperty'.

The problem is that now my signature has the big ugly Expression<...>
in there. It might confuse people. Additionally, if I wanted to
execute the lambda, I would have to use reflection (through
Expression.Compile or the PropertyInfo).

So, I want the method to have a signature like this:

private static string getProperty<TValue>(Func<TDataObject, TValue>
propertyChooser);

I then want to create the Expression dynamically (runtime intensive,
I'd imagine). That way I keep a dumbed down interface. I am curious
whether this is even possible.
 
P

Peter Duniho

Jehu said:
[...]
I'm asking whether you can create an Expression from a Func.

You can, but your question is not specific enough to know whether the
ways that you can are useful to you or not.
[...]
string propertyName = getProperty(a => a.MyProperty); // should return
'MyProperty'.

The problem is that now my signature has the big ugly Expression<...>
in there. It might confuse people. Additionally, if I wanted to
execute the lambda, I would have to use reflection (through
Expression.Compile or the PropertyInfo).

So, I want the method to have a signature like this:

private static string getProperty<TValue>(Func<TDataObject, TValue>
propertyChooser);

I then want to create the Expression dynamically (runtime intensive,
I'd imagine). That way I keep a dumbed down interface. I am curious
whether this is even possible.

I am confused as to why, if you don't want to execute the expression at
some point, you ever want the lambda represented as an expression. Is
it solely so that you can retrieve the name of the property from
something that uses the property itself, as you mentioned above?

It is easy enough to pass the delegate from the lambda expression
directly, and then create an Expression<Func<T, TResult>> from that.
But that expression will not have the same characteristics as the one
you get from your code example. It would simply be a call into the
anonymous method the lambda expression wound up creating.

To get at the PropertyInfo object, you'd have to reflect on the
anonymous method itself, and extract the PropertyInfo from the method
body. I think that's still possible, but it's not as convenient as the
approach your original example uses.

If I have time later, I'll try to put together a code example or two.
But in the meantime, if you can elaborate on why you feel like you need
to use the lambda expression in two completely different ways. In your
code example, you seem to just want the name of the property.

But note that you also get a PropertyInfo object out of it, which you
could easily use to retrieve the property's value without having to
execute any specific expression or lambda at all. What is it about the
anonymous method version of the lambda expression that has value for
your situation? When would you ever actually want to execute that
expression?

I understand your concern about the method signature, but honestly your
approach to the code is already off the beaten path enough that you have
traded one maintenance issue for another. I understand the benefit of
not having string literals in your code representing property names, but
depending on what you would otherwise do with those literals, I think
there are probably alternatives that would work better than the
expression-based approach.

In any case, given the complexity of this particular approach, I don't
really think that a little thing like whether the method signature has
the Expression<T> in it or not is really that important.

Pete
 
P

Peter Duniho

Peter said:
[...]
If I have time later, I'll try to put together a code example or two.

Okay, here's a short code example that shows a variety of techniques,
including the one you posted initially. Hopefully, it's obvious from
the method names what technique each method is demonstrating. But I put
comments in to try to describe them too.

I should point out that the reflection-based extraction of the property
name and value from a Func<T, TResult> delegate is very fragile. The
code doesn't do any proper parsing of the IL; it just scans for the
first byte that looks like it could be the right instruction. I assume
this isn't an issue for you, since you already have the requirement that
the original lambda be in a precise format. But it's definitely
something to be aware of if you decide at some point to try to extend
this technique to other things.

If you have any questions, just ask.

Pete




using System;
using System.Linq.Expressions;
using System.Reflection;

namespace TestExpressionPropertyInfo
{
class Program
{
class A
{
public int Integer { get; set; }
}

static void Main(string[] args)
{
Expression<Func<A, int>> expr = a => a.Integer;
Func<A, int> func = a => a.Integer;

Console.WriteLine(PropertyName(expr));

MethodCallExpression expr1 = PropertyValueExpression(func);

A a1 = new A();

a1.Integer = 5;

Console.WriteLine("returned: " + (int)CallExpression(expr1, a1));

Console.WriteLine("property name: " + PropertyName(func));

Console.WriteLine("property value: " + PropertyValue(func, a1));

Console.ReadLine();
}


// Your original idea - returns the property name from the
// Expression object

static string PropertyName<TObject,
TProperty>(Expression<Func<TObject, TProperty>> expr)
{
return ((PropertyInfo)((MemberExpression)expr.Body).Member).Name;
}


// One possible interpretation of "create an expression from
// a Func<T, TResult>". Note that this does not get you the name
// of the property; just the value (and then only if the delegate
// passed in actually does that)

static MethodCallExpression PropertyValueExpression<TObject,
TProperty>(Func<TObject, TProperty> func)
{
ConstantExpression exprObject = func.Target != null ?
Expression.Constant(func.Target) : null;
ParameterExpression exprParameter =
Expression.Parameter(typeof(TObject));

return Expression.Call(exprObject, func.Method, exprParameter);
}


// Given the previously returned Expresison, this method will
// actually invoke it to retrieve the value from the property
static object CallExpression(MethodCallExpression expr, object
objParameter)
{
ParameterExpression exprParameter =
(ParameterExpression)expr.Arguments[0];
LambdaExpression exprLambda = Expression
.Lambda(expr, exprParameter);
Delegate invoker = exprLambda.Compile();

return invoker.DynamicInvoke(objParameter);
}


// This reflection-based method gets the actual IL for the
// delegate's method's body, looks for a likely method call,
// looks up the method name, and then returns the portion of
// the special method name that came from the property name

static string PropertyName<TObject, TProperty>(Func<TObject,
TProperty> func)
{
MethodInfo method = MethodInfoFromIL<TObject>(
func.Method.GetMethodBody().GetILAsByteArray());
string strName = method.Name;

if (method.IsSpecialName && strName.StartsWith("get_"))
{
return strName.Substring(4);
}

return null;
}


// This method uses the same reflection technique to get the
// MethodInfo object, but then actually invokes the method
// to get the property value

static TProperty PropertyValue<TObject, TProperty>(Func<TObject,
TProperty> func, TObject t)
{
MethodInfo method = MethodInfoFromIL<TObject>(
func.Method.GetMethodBody().GetILAsByteArray());

return (TProperty)method.Invoke(t, null);
}


// Helper method to search the IL that came from the delegate's
// method's body for a likely call site to the property's getter

static MethodInfo MethodInfoFromIL<T>(byte[] rgb)
{
for (int ib = 0; ib < rgb.Length - 4; ib++)
{
// 0x6f is the token for a 'callvirt' instruction
// next four bytes should be a method token
if (rgb[ib] == 0x6f)
{
int token = BitConverter.ToInt32(rgb, ib + 1);

return MethodInfoFromToken<T>(token);
}
}

return null;
}


// Helper method to map a token to an actual MethodInfo
// object. Obviously for performance-sensitive applications,
// a dictionary could be used to improve speed here.

static MethodInfo MethodInfoFromToken<T>(int token)
{
foreach (MethodInfo method in typeof(T)
.GetMethods(BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance))
{
if (method.MetadataToken == token)
{
return method;
}
}

return null;
}
}
}
 
J

Jehu Galeahsa

Peter said:
[...]
If I have time later, I'll try to put together a code example or two.

Okay, here's a short code example that shows a variety of techniques,
including the one you posted initially.  Hopefully, it's obvious from
the method names what technique each method is demonstrating.  But I put
comments in to try to describe them too.

I should point out that the reflection-based extraction of the property
name and value from a Func<T, TResult> delegate is very fragile.  The
code doesn't do any proper parsing of the IL; it just scans for the
first byte that looks like it could be the right instruction.  I assume
this isn't an issue for you, since you already have the requirement that
the original lambda be in a precise format.  But it's definitely
something to be aware of if you decide at some point to try to extend
this technique to other things.

If you have any questions, just ask.

Pete

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace TestExpressionPropertyInfo
{
   class Program
   {
     class A
     {
       public int Integer { get; set; }
     }

     static void Main(string[] args)
     {
       Expression<Func<A, int>> expr = a => a.Integer;
       Func<A, int> func = a => a.Integer;

       Console.WriteLine(PropertyName(expr));

       MethodCallExpression expr1 = PropertyValueExpression(func);

       A a1 = new A();

       a1.Integer = 5;

       Console.WriteLine("returned: " + (int)CallExpression(expr1, a1));

       Console.WriteLine("property name: " + PropertyName(func));

       Console.WriteLine("property value: " + PropertyValue(func,a1));

       Console.ReadLine();
     }

     // Your original idea - returns the property name from the
     // Expression object

     static string PropertyName<TObject,
TProperty>(Expression<Func<TObject, TProperty>> expr)
     {
       return ((PropertyInfo)((MemberExpression)expr.Body).Member).Name;
     }

     // One possible interpretation of "create an expression from
     // a Func<T, TResult>". Note that this does not get you the name
     // of the property; just the value (and then only if the delegate
     // passed in actually does that)

     static MethodCallExpression PropertyValueExpression<TObject,
TProperty>(Func<TObject, TProperty> func)
     {
       ConstantExpression exprObject = func.Target != null ?
         Expression.Constant(func.Target) : null;
       ParameterExpression exprParameter =
         Expression.Parameter(typeof(TObject));

       return Expression.Call(exprObject, func.Method, exprParameter);
     }

     // Given the previously returned Expresison, this method will
     // actually invoke it to retrieve the value from the property
     static object CallExpression(MethodCallExpression expr, object
objParameter)
     {
       ParameterExpression exprParameter =
         (ParameterExpression)expr.Arguments[0];
       LambdaExpression exprLambda = Expression
         .Lambda(expr, exprParameter);
       Delegate invoker = exprLambda.Compile();

       return invoker.DynamicInvoke(objParameter);
     }

     // This reflection-based method gets the actual IL for the
     // delegate's method's body, looks for a likely method call,
     // looks up the method name, and then returns the portion of
     // the special method name that came from the property name

     static string PropertyName<TObject, TProperty>(Func<TObject,
TProperty> func)
     {
       MethodInfo method = MethodInfoFromIL<TObject>(
         func.Method.GetMethodBody().GetILAsByteArray());
       string strName = method.Name;

       if (method.IsSpecialName && strName.StartsWith("get_"))
       {
         return strName.Substring(4);
       }

       return null;
     }

     // This method uses the same reflection technique to get the
     // MethodInfo object, but then actually invokes the method
     // to get the property value

     static TProperty PropertyValue<TObject, TProperty>(Func<TObject,
TProperty> func, TObject t)
     {
       MethodInfo method = MethodInfoFromIL<TObject>(
         func.Method.GetMethodBody().GetILAsByteArray());

       return (TProperty)method.Invoke(t, null);
     }

     // Helper method to search the IL that came from the delegate's
     // method's body for a likely call site to the property's getter

     static MethodInfo MethodInfoFromIL<T>(byte[] rgb)
     {
       for (int ib = 0; ib < rgb.Length - 4; ib++)
       {
         // 0x6f is the token for a 'callvirt' instruction
         // next four bytes should be a method token
         if (rgb[ib] == 0x6f)
         {
           int token = BitConverter.ToInt32(rgb, ib + 1);

           return MethodInfoFromToken<T>(token);
         }
       }

       return null;
     }

     // Helper method to map a token to an actual MethodInfo
     // object.  Obviously for performance-sensitive applications,
     // a dictionary could be used to improve speed here.

     static MethodInfo MethodInfoFromToken<T>(int token)
     {
       foreach (MethodInfo method in typeof(T)
         .GetMethods(BindingFlags.Public | BindingFlags.NonPublic |
         BindingFlags.Static | BindingFlags.Instance))
       {
         if (method.MetadataToken == token)
         {
           return method;
         }
       }

       return null;
     }
   }



}- Hide quoted text -

- Show quoted text -

Simply put... woah! You hit is right on the head and kept on going.

Here was my situation: I use binding in WinForms to display data
objects from my data layer. When binding, I am required to raising
INotifyPropertyChanged events whenever a property is changed.
Furthermore, I am required to detect errors (IDataErrorInfo), maintain
state and convert enums into bindable types. It is a really complex
approach to WinForms binding.

Since my raw DOs can't be directly bound to the UI, I create "wrapper"
classes. 80% of the time, the properties in the wrappers simply call
the properties of the DO. Unfortunately, since the wrapper base class
is maintaining state for me and dealing with notifications, it would
be repetitive and error-prone to manually get/set the DOs properties.
So, I created two methods: GetValue and SetValue that use reflection
to grab the values from the underlying DOs.

Technically, I could simply create a property in the base class that
returns the current state of the DO. Then, in the setters, I would
simply raise the notification. However, the
INotifyPropertyChanged.PropertyChanged event takes the name of the
property as a string. I want to avoid using string literals, if
possible, since my code tends to go through large changes now and
then. I figured I would use expression trees to eliminate this
refactoring nightmare. Since I decided to go down that path, I also
decided that paying for a reflective call wasn't such a big deal
either. Hence, GetValue and SetValue.

My curiousity was whether I could avoid the runtime cost using
Expression, aka avoiding the dynamic invocation of the lambda. But, I
think the time it would take to build the Expression and then extract
the property name from it would take even longer to run.

Of course, all of this is attached to a user interface, so reflection
isn't hurting my runtime performance. I guess I will stick with the
Expression syntax and be happy. Your examples were great, and good
enough to warn me away from using that logic. Folks here are going to
have a hard enough time using my library as it is, now, without
needing to try to maintain that level of complexity.

I really appreciate you taking the time to write the examples.
 
P

Peter Duniho

Jehu said:
[...]
Of course, all of this is attached to a user interface, so reflection
isn't hurting my runtime performance. I guess I will stick with the
Expression syntax and be happy. Your examples were great, and good
enough to warn me away from using that logic. Folks here are going to
have a hard enough time using my library as it is, now, without
needing to try to maintain that level of complexity.

I really appreciate you taking the time to write the examples.

Sure, happy to help. And yes, I agree that to do more than you're
already doing would greatly increase the complexity of an
already-complex system. You're probably better off sticking with what
you're doing now.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top