Expression> - Get Property's calling object instance without Compile()

c# expression-trees lambda

Question

EDIT: Updated example to what I'm actually doing.

EDIT 2: The why:
My class "takes hold" of a property setter (or method, anonymous or not) and "controls" it for a period of time. The user could try and attach another instance of my class and attach that to a property that is already "controlled." I need a way to detect these conflicts reliably. I could forego the () => { property } method but that requires the user to wrap the target property in a method and, if he/she wants conflict detection, to pass in the object containing the property. Doing it that way introduces higher risk of bugs as they may type in the wrong object and the class wouldn't have any means to check for them.

I am unable to utilize the Lambda Compile() because I am targeting AOT in addition to JIT.


I have a method that takes an

Expression<Func<T>> 

as an argument. The Expression always evaluates to a property with a setter of Type T.

private static TargetInfo GetTargetInfo<T>(Expression<Func<T>> _propertyExpression, out Action<T> _setter)
{
    //Get Property info
    var propInfo = ((MemberExpression)_propertyExpression.Body).Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException("_propertyExpression must be a property.");


    var declType = propInfo.DeclaringType;
    var methodInfo = propInfo.GetSetMethod(true) ?? declType.GetProperty(propInfo.Name).GetSetMethod(true);
    if (methodInfo == null)
        throw new Exception("Could not create setter from property '" + _propertyExpression + "'");
    var isStaticProp = methodInfo.IsStatic;

    //Get Target Object
    object targetObject = null;
    var memberExp = _propertyExpression.Body as MemberExpression;
    var bodyExp = memberExp.Expression;
    if (bodyExp != null)
// PROBLEM LINE BELOW - Can't use Compile()  *********************************
        targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();   
// PROBLEM LINE ABOVE  *******************************************************
    else if (isStaticProp)
        targetObject = memberExp.Member.DeclaringType;
    else
        throw new Exception("Could not determine target object.  Use Action<T> overload. (no conflict detection)");


    //Cache setter of property
    if (isStaticProp)
        _setter = (Action<T>) Delegate.CreateDelegate(typeof (Action<T>), methodInfo);
    else
        _setter = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), targetObject, methodInfo);

    return new TargetInfo(methodInfo, targetObject);
}

The expression (_propertyExpression) is always of a property. And the property always has a setter.

  • I need to extract the property's setter as Action (which I can do no problem)
  • I also need the instance of the object containing this property without using Compile() as it is not available on some of the target platforms I am targeting.

The reason I need the instance is to determine whether or not another object instance of my class is currently utilizing that property SETTER on THAT object. (No Threading, just usage over a span of time) I store the object Instance and property setter info together as a key, if two keys that are equal that exist then there is a conflict and it is handled based on the user's configuration settings of my class.

I am able to get the object instance for simple expressions like:

() => MyProperty

or

() => MyObjectInst.PropertyFoo

or

() => MyStaticClass.PropertyFooBar

No Sweat!

But what if the user does this:

//Need instance of 'someObject' here.
() => SomeArray[idx].someObject.propertyA

or blow my top:

//Need instance of 'someField[4]' here
() => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB

AAAK!

I've been looking at this for a while and I BELIEVE that I need to traverse the tree BACK to the base object (ConstantExpression) then start evaluating back UP the tree using the info collected walking to the front. Given the examples above I decided that I need "bigger guns".

  1. Is there an easier way to get the property's caller's instance other than completely walking the tree WITHOUT using Compile()? Please explain if so!

  2. If not 1. If anyone could point me in the right direction on how to traverse the tree and handle stuff like the above. That would be great. I'm not finding a whole lot of info on traversing Expression Trees, expression types, etc. Even a reference to a recommended book specific to the subject would be helpful.

  3. sigh Should I just give up and force the user to use simple expressions. ie. Do not allow the user to type in lengthy property access lines.

Clarification: The setter is being cached for use by a mechanism class "FOO" that will be setting this value an UNKNOWN range of values of type T over some defined period of time. The object instance is cached and used as a key to detect the case that another instance of FOO tries to attach and set values to the same property on that same object. The object instance is used to detect these conflicts and also to keep track of all of the "FOO"s attached to any particular object. The user can attach multiple "FOO"s to the same object, to different properties. In the case that the user attaches an instance of FOO to a property on an object that already has a FOO attached for that property, a conflict event occurs. FOO can be configured on how to handle when that happens.

Popular Answer

Here's the problems with your suggested approaches:

  1. Is there an easier way to get the property's caller's instance other than completely walking the tree WITHOUT using Compile()? Please explain if so!

Short answer, no. Expressions are meant to be compiled. Either into .NET Funcs/Actions or some other platform (LINQ-to-Entities essentially compiles them into SQL). If you don't want to compile it, you're probably using the wrong tool.

  1. If not 1. If anyone could point me in the right direction on how to traverse the tree and handle stuff like the above. That would be great. I'm not finding a whole lot of info on traversing Expression Trees, expression types, etc. Even a reference to a recommended book specific to the subject would be helpful.

The best way to traverse an Expression tree is by inheriting from ExpressionVisitor. A good blog to start with would be Matt Warren's blog http://blogs.msdn.com/b/mattwar/, read the series on implementing IQueryable. But no, it's not easy.

One could (theoretically) inherit from ExpressionVisitor to walk down/up the chain to the original instance. But you would then have to walk back up/down the chain somehow, and the easiest way to do that would be by compiling the child Expressions. You could, theoretically, use Reflection to walk back, as your answer tries, but I hope you're distinctly getting the impression you have chosen the wrong tool if your No-Compiling stance is iron-clad.

  1. sigh Should I just give up and force the user to use simple expressions.

You haven't outlined the benefits/drawbacks of this.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why