Cast function expression tree from object - c#

I've ended up with a situation where an function expression tree Expression<Func<TClass, TProperty>> is assigned to a global variable of type object and then later in the code I need to call a different method with the expression. I can't change the global objects type; it has to be object.
The code won't compile when trying to call the second method with the global object unless I cast the object as Expression<Func<TClass, TProperty>>. The problem is I don't know what TProperty is at the point that the second method is called.
I've created a quick demo app to illustrate the point (c# console app written in VS2010) - the real application looks nothing like this.
using System;
using System.Linq.Expressions;
namespace FuncExpressionTree
{
public class ViewModel
{
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
public class Helper<T>
where T : ViewModel
{
private object _global;
public void Execute()
{
AssignToGlobal((T vm) => vm.StringProperty);
ProcessGlobal();
AssignToGlobal((T vm) => vm.IntProperty);
ProcessGlobal();
}
public void AssignToGlobal<TClass, TProperty>(Expression<Func<TClass, TProperty>> expression)
{
_global = expression;
}
public void ProcessGlobal()
{
// invalid cast exception thrown when IntProperty is assigned to _global
AssignToGlobal((Expression<Func<T, string>>)_global);
}
}
class Program
{
static void Main(string[] args)
{
(new Helper<ViewModel>()).Execute();
}
}
}
If we focus on the Execute() method.
First global is assigned expression for the string property.
ProcessGlobal executes and works because I'm casting to Expression<Func<T, string>>.
Next global is assigned expression for int property.
ProcessGlobal again executes but its at this point that an invalid cast exception is thrown. It would work if I changed it to cast Expression<Func<T, int>> instead but then the string property wouldn't work. Also Expression<Func<T, object>> throws an invalid cast exception.
I feel like Im missing something and that it should be possible to do something with the System.Linq.Expressions namespace to dynamically invoke the the second method (eg AssignToGlobal within ProcessGlobal in the above example).
So how can I get this to work in a generic way?

public void ProcessGlobal()
{
var globalType = _global.GetType(); // globalType = Expression<Func<TClass, TProperty>>
var functionType = globalType.GetGenericArguments()[0]; // functionType = Func<TClass, TProperty>
var functionGenericArguments = functionType.GetGenericArguments(); // v = [TClass, TProperty]
var method = this.GetType().GetMethod("AssignToGlobal").MakeGenericMethod(functionGenericArguments); //functionGenericArguments = AssignToGlobal<TClass, TProperty>
method.Invoke(this, new[] { this._global }); // Call AssignToGlobal<TClass, TProperty>)(this._global);
}

Related

Changing the return type of an expression<func<>>

Say I have an Expression<Func<T,object>> is it possible to dynamically change the return type based on a Type variable to be something like Expression<Func<T,int>>
I have the following class:
public class ImportCheck<T> {
public int id { get; set; }
public string Name { get; set; }
public Type Type { get; set; }
public bool Required { get; set; }
public int? MinLength { get; set; }
public int? MaxLength { get; set; }
public string Value { get; set; }
public Expression<Func<T, object>> AssociatedProperty { get; set; }
}
I have a List<ImportCheck<Contact>> which I loop through and for each one set a property on the Contact object (the properties are all different types). To enable me to set the property of nested objects I need the result type to be the same as the target type.
If all the properties of the contact were say int then what I have now would work fine it's the fact that I have a list of different types that is causing me the headache.
This is how I set a sub property:
private static Action<M, R> MakeSet<M, R>(Expression<Func<M, R>> fetcherExp) {
if (fetcherExp.Body.NodeType != ExpressionType.MemberAccess) {
throw new ArgumentException(
"This should be a member getter",
"fetcherExp");
}
// Input model
var model = fetcherExp.Parameters[0];
// Input value to set
var value = Expression.Variable(typeof(R), "v");
// Member access
var member = fetcherExp.Body;
// We turn the access into an assignation to the input value
var assignation = Expression.Assign(member, value);
// We wrap the action into a lambda expression with parameters
var assignLambda = Expression.Lambda<Action<M, R>>(assignation, model, value);
return assignLambda.Compile();
}
This is then called like MakeSet(member)(target,value) where member is the Expression<Func<T,object>> target is the object and value is the value to set the property to.
Please find the example below:
public class ReturnTypeVisitor<TSource, TReturnValue> : ExpressionVisitor{
protected override Expression VisitLambda<T>(Expression<T> node)
{
var delegateType = typeof(Func<,>).MakeGenericType(typeof(TSource), typeof(TReturnValue));
return Expression.Lambda(delegateType, Visit(node.Body), node.Parameters);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.DeclaringType == typeof(TSource))
{
return Expression.Property(Visit(node.Expression), node.Member.Name);
}
return base.VisitMember(node);
}
}
Usage:
public class Foo{
public Bar Bar { get; set; }
}
public class Bar { }
Expression<Func<Foo, object>> expression = p => p.Bar;
Expression<Func<Foo, Bar>> stronglyTypedReturnValue = (Expression<Func<Foo, Bar>>)new ReturnTypeVisitor<Foo, Bar>().Visit(expression);
Sure; you can create a new expression tree with a cast from object to whatever type you want (no guarrantees the cast will hold, of course) - and you can use parts of the old expression tree (namely the entire lambda body) in your new expression tree.
However, even if you create such a thing, note that if you want to express the type of the expresion statically - e.g. Expression<Func<T,int>> you're going to need to know the type statically. Generics would work - but a runtime Type variable isn't.
There are several problems with your approach:
You assume that fetcherExp.Body is a member access, e.g. obj.TheProperty. However, if the expression is of type Expression<Func<T,object>> then any value-type property will be represented as a "Convert(obj.TheProperty)".
You assume there's a setter corresponding to the getter.
You assume that the Type property is correct.
I suggest you approach this problem differently. Instead of dealing with improperly typed Expression<Func<T,object>> objects and trying to generate setters (and getters?) from that, I suggest you start from an accurately typed Expression<Func<T,TProperty>> - or even just a PropertyInfo and generate typed getters and setters. Once you have a Func<T,TProperty> getter and an Action<T,TProperty> setter, you can easily wrap those to generate less specific actions and funcs:
public static Action<T,object> UntypeSetter<T,TProperty>(Action<T,TProperty> typedSetter) =>
(o, val) => typedSetter(o, (TProperty)val);
A similar approach is useful for getters (but this only matters for getters of value-type properties since covariance means that reference type getters can all be cast to Action<T,object>).
If you absolutely need maximal runtime performance, you can do exactly the same wrapping trick with Expression<...>s and inline the nested call to typedSetter, but note that you're not winning that much; the difference between one and two delegate calls is unlikely to matter for most applications.
TL;DR: Don't use Expression<Func<T,object>> as an intermediate representation of an untyped property; doing so throws away type information useful to creating getters/setters. Instead, use a typed expression Expression<Func<T,TProperty>> to easily generate untyped getters and setters, and pass those around as your intermediate representation.
Just use Expression.Convert on expression body:
public static class ExpressionHelper
{
public static Expression<Func<TSource, TConvertedResult>> ConvertResult<TSource, TResult, TConvertedResult>(Expression<Func<TSource, TResult>> expression)
{
return Expression.Lambda<Func<TSource, TConvertedResult>>(Expression.Convert(expression.Body, typeof(TConvertedResult)), expression.Parameters);
}
}
Tests:
[TestFixture]
public class ExpressionHelperTest
{
public class BaseClass
{
public BaseClass(bool boolean)
{
Boolean = boolean;
}
public bool Boolean { get; set; }
}
public class DerivedClass : BaseClass
{
public DerivedClass(bool boolean, int integer) : base(boolean)
{
Integer = integer;
}
public int Integer { get; set; }
}
[Test]
public void ConvertResult_Simple_Test()
{
Expression<Func<int, bool>> notNullExpression = i => i != 0;
Expression<Func<int, object>> notNullObjectResultExpression = ExpressionHelper.ConvertResult<int, bool, object>(notNullExpression);
Func<int, bool> notNull = notNullExpression.Compile();
Func<int, object> notNullObjectResult = notNullObjectResultExpression.Compile();
Assert.True(notNull(1));
Assert.False(notNull(0));
Assert.AreEqual(true, notNullObjectResult(1));
Assert.AreEqual(false, notNullObjectResult(0));
Assert.Pass();
}
[Test]
public void ConvertResult_Inheritance_Test()
{
Expression<Func<(bool boolean, int integer), DerivedClass>> derivedClassExpression = x => new DerivedClass(x.boolean, x.integer);
Expression<Func<(bool boolean, int integer), BaseClass>> baseClassExpression = ExpressionHelper.ConvertResult<(bool boolean, int integer), DerivedClass, BaseClass>(derivedClassExpression);
Expression<Func<(bool boolean, int integer), DerivedClass>> derivedClassFromBaseClassExpression = ExpressionHelper.ConvertResult<(bool boolean, int integer), BaseClass, DerivedClass>(baseClassExpression);
Func<(bool boolean, int integer), DerivedClass> derivedClass = derivedClassExpression.Compile();
Func<(bool boolean, int integer), BaseClass> baseClass = baseClassExpression.Compile();
Func<(bool boolean, int integer), DerivedClass> derivedClassFromBaseClass = derivedClassFromBaseClassExpression.Compile();
(bool boolean, int integer) trueAndOne = (true, 1);
(bool boolean, int integer) falseAndZero = (false, 0);
Assert.True(derivedClass(trueAndOne).Boolean);
Assert.False(derivedClass(falseAndZero).Boolean);
Assert.AreEqual(1, derivedClass(trueAndOne).Integer);
Assert.AreEqual(0, derivedClass(falseAndZero).Integer);
Assert.True(baseClass(trueAndOne).Boolean);
Assert.False(baseClass(falseAndZero).Boolean);
Assert.True(derivedClassFromBaseClass(trueAndOne).Boolean);
Assert.False(derivedClassFromBaseClass(falseAndZero).Boolean);
Assert.AreEqual(1, derivedClassFromBaseClass(trueAndOne).Integer);
Assert.AreEqual(0, derivedClassFromBaseClass(falseAndZero).Integer);
Assert.Pass();
}
}
Here is a simple way to change the return value of an Expression<Func<>> for a very simple case:
Expression<Func<int, bool>> x = t => t > 1;
var prmi = Expression.Parameter(typeof(int), "i");
var lambda = Expression.Lambda<Func<int, int>>(Expression.Convert(Expression.Invoke(x,prmi), typeof(int)),prmi);
var i = lambda.Compile().Invoke(2); //returns an int

Generic constraints with C# Expression<TDelegate> - Cannot implicitly convert Type

I've started using C# Expression constructs, and I've got a question about how generics are applied in the following situation:
Consider I have a type MyObject which is a base class for many different types. Inside this class I have the following code:
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<MyObject, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson) where T : MyObject
{
StringIndexExpression = expression;
}
This is how I use DefineStringIndexer:
public class MyBusinessObject : MyObject
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}
However in the assignment inside DefineStringIndexer I get the compile error:
Cannot implicitly convert type
System.Linq.Expression.Expression< MyObject, string, bool > to
System.Linq.Expression.Expression < MyBusinessObject, string, bool >>
Can I use Generics with C# Expressions in this situation? I want to use T in DefineStringIndexer so I can avoid casting MyObject inside the lambda.
The assignment will not work, because the Func<MyBusinessObject,string,bool> type is not assignment-compatible with Func<MyObject,string,bool>. However, the parameters of the two functors are compatible, so you can add a wrapper to make it work:
protected void DefineStringIndexer<T>(Func<T,string,bool> expresson) where T : MyObject {
StringIndexExpression = (t,s) => expression(t, s);
}
Would this work better for you?
Edit: Added <T> to constraint - think you will need that :)
class MyObject<T>
{
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<T, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson)
where T : MyObject<T> // Think you need this constraint to also have the generic param
{
StringIndexExpression = expression;
}
}
then:
public class MyBusinessObject : MyObject<MyBusinessObject>
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}

Attribute Constructor With Lambda

It is possible to do this:
public static void SomeMethod<TFunc>(Expression<TFunc> expr)
{
//LambdaExpression happily excepts any Expession<TFunc>
LambdaExpression lamb = expr;
}
and call it elsewhere passing a lambda for the parameter:
SomeMethod<Func<IQueryable<Person>,Person>>( p=>p.FirstOrDefault());
I would instead like to pass an expression as a parameter to an attribute constructor.
Is it possible to do the below?
class ExpandableQueryAttribute: Attribute {
private LambdaExpression someLambda;
//ctor
public ExpandableQueryMethodAttribute(LambdaExpression expression)
{
someLambda = expression
}
}
//usage:
static LambdaExpression exp =
(Expression<Func<IQueryable<Person>, Person>>)
(p => p.FirstOrDefault());
[ExpandableQueryAttribute(exp)] //error here
// "An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type"
My goal is to specify a method or lambda in the constructor of the attribute(even if I have to declare a full named method and pass the name of the method somehow, that'd be fine to).
Parameter types can change, but it is important that the attribute constructor can take that parameter and in some way be able to assign it to a field of type LambdaExpression
I want the declaration of the lambda/method to be just above the call to the attribute constructor, or inline, so that you don't have to go far to see what is being passed.
So these alternatives would be fine, but no luck getting them to work:
public static ... FuncName(...){...}
[ExpandableQueryAttribute(FuncName)]
// ...
or
//lambdas aren't allowed inline for an attribute, as far as I know
[ExpandableQueryAttribute(q => q.FirstOrDefault())]
// ...
The existing work around is to pass a number ID to the constructor(satisfying the "argument must be a constant" requirement), which is used by the constructor to do a lookup in a dictionary where expressions have been added previously. Was hoping to improve/simplify this, but I have a feeling it doesn't get any better due to limitations on attribute constructors.
how about this:
class ExpandableQueryAttribute : Attribute
{
private LambdaExpression someLambda;
//ctor
public ExpandableQueryAttribute(Type hostingType, string filterMethod)
{
someLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
// could also use a static method
}
}
this should let you assign your lambda to a field and then suck it in at runtime, although in general I would prefer to use something like PostSharp to do this at compile time.
simple usage example
public class LambdaExpressionAttribute : Attribute
{
public LambdaExpression MyLambda { get; private set; }
//ctor
public LambdaExpressionAttribute(Type hostingType, string filterMethod)
{
MyLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
}
}
public class User
{
public bool IsAdministrator { get; set; }
}
public static class securityExpresions
{
public static readonly LambdaExpression IsAdministrator = (Expression<Predicate<User>>)(x => x.IsAdministrator);
public static readonly LambdaExpression IsValid = (Expression<Predicate<User>>)(x => x != null);
public static void CheckAccess(User user)
{
// only for this POC... never do this in shipping code
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
var filters = method.GetCustomAttributes(typeof(LambdaExpressionAttribute), true).OfType<LambdaExpressionAttribute>();
foreach (var filter in filters)
{
if ((bool)filter.MyLambda.Compile().DynamicInvoke(user) == false)
{
throw new UnauthorizedAccessException("user does not have access to: " + method.Name);
}
}
}
}
public static class TheClass
{
[LambdaExpression(typeof(securityExpresions), "IsValid")]
public static void ReadSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("read something");
}
[LambdaExpression(typeof(securityExpresions), "IsAdministrator")]
public static void WriteSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("wrote something");
}
}
static void Main(string[] args)
{
User u = new User();
try
{
TheClass.ReadSomething(u, new object());
TheClass.WriteSomething(u, new object());
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
This is not possible because what you can pass into an attribute needs to fit into the CLR's binary DLL format and there is no way to encode arbitrary object initialization. For the same you you cannot pass a nullable value for example. The restrictions are very strict.
Although you cannot have complex constructor for attributes, in some situation a work-aound is to have a public property for that attribute and update it at run-time.
self point to an object of the class that contains some attributes on its properties. LocalDisplayNameAttribute is a custom attribute.
The following code will set ResourceKey property of my custom attribute class at run-time. Then at that point you can override DisplayName to outpiut whatever text you want.
static public void UpdateAttributes(object self)
{
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
{
LocalDisplayNameAttribute attr =
prop.Attributes[typeof(LocalDisplayNameAttribute)]
as LocalDisplayNameAttribute;
if (attr == null)
{
continue;
}
attr.ResourceKey = prop.Name;
}
}
Use dymanic linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You can make the attribute's constructor take a string which evaluates to an expression.

Assign Property with an ExpressionTree

I'm playing around with the idea of passing a property assignment to a method as an expression tree. The method would Invoke the expression so that the property gets assigned properly, and then sniff out the property name that was just assigned so I can raise the PropertyChanged event. The idea is that I'd like to be able to use slim auto-properties in my WPF ViewModels and still have the PropertyChanged event fired off.
I'm an ignoramus with ExpressionTrees, so I'm hoping someone can point me in the right direction:
public class ViewModelBase {
public event Action<string> PropertyChanged = delegate { };
public int Value { get; set; }
public void RunAndRaise(MemberAssignment Exp) {
Expression.Invoke(Exp.Expression);
PropertyChanged(Exp.Member.Name);
}
}
The problem is I'm not sure how to call this. This naive attempt was rejected by the compiler for reasons that I'm sure will be obvious to anyone who can answer this:
ViewModelBase vm = new ViewModelBase();
vm.RunAndRaise(() => vm.Value = 1);
EDIT
Thank you #svick for the perfect answer. I moved one little thing around and made it into an extension method. Here's the complete code sample with unit test:
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
MyViewModel vm = new MyViewModel();
bool ValuePropertyRaised = false;
vm.PropertyChanged += (s, e) => ValuePropertyRaised = e.PropertyName == "Value";
vm.SetValue(v => v.Value, 1);
Assert.AreEqual(1, vm.Value);
Assert.IsTrue(ValuePropertyRaised);
}
}
public class ViewModelBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void OnPropertyChanged(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MyViewModel : ViewModelBase {
public int Value { get; set; }
}
public static class ViewModelBaseExtension {
public static void SetValue<TViewModel, TProperty>(this TViewModel vm, Expression<Func<TViewModel, TProperty>> exp, TProperty value) where TViewModel : ViewModelBase {
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
propertyInfo.SetValue(vm, value, null);
vm.OnPropertyChanged(propertyInfo.Name);
}
}
You can't do it this way. First, lambda expressions can be converted only to delegate types or Expression<T>.
If you change the signature of the method (for now ignoring its implementation) to public void RunAndRaise(Expression<Action> Exp), the compiler complains that “An expression tree may not contain an assignment operator”.
You could do it by specifying the property using lambda and the value you want to set it to in another parameter. Also, I didn't figure out a way to access the value of vm from the expression, so you have to put that in another parameter (you can't use this for that, because you need the proper inherited type in the expression):see edit
public static void SetAndRaise<TViewModel, TProperty>(
TViewModel vm, Expression<Func<TViewModel, TProperty>> exp, TProperty value)
where TViewModel : ViewModelBase
{
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
propertyInfo.SetValue(vm, value, null);
vm.PropertyChanged(propertyInfo.Name);
}
Another possibility (and one I like more) is to raise the event from setter specifically using lambda like this:
private int m_value;
public int Value
{
get { return m_value; }
set
{
m_value = value;
RaisePropertyChanged(this, vm => vm.Value);
}
}
static void RaisePropertyChanged<TViewModel, TProperty>(
TViewModel vm, Expression<Func<TViewModel, TProperty>> exp)
where TViewModel : ViewModelBase
{
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
vm.PropertyChanged(propertyInfo.Name);
}
This way, you can use the properties as usual, and you could also raise events for computed properties, if you had them.
EDIT: While reading through Matt Warren's series about implementing IQueryable<T>, I realized I can access the referenced value, which simplifies the usage of RaisePropertyChanged() (although it won't help much with your SetAndRaise()):
private int m_value;
public int Value
{
get { return m_value; }
set
{
m_value = value;
RaisePropertyChanged(() => Value);
}
}
static void RaisePropertyChanged<TProperty>(Expression<Func<TProperty>> exp)
{
var body = (MemberExpression)exp.Body;
var propertyInfo = (PropertyInfo)body.Member;
var vm = (ViewModelBase)((ConstantExpression)body.Expression).Value;
vm.PropertyChanged(vm, new PropertyChangedEventArgs(propertyInfo.Name));
}
Here is a generaic solution that can give you an Action for assignment from an expression to specify the left hand side of assignment, and a value to assign.
public Expression<Action> Assignment<T>(Expression<Func<T>> lvalue, T rvalue)
{
var body = lvalue.Body;
var c = Expression.Constant(rvalue, typeof(T));
var a = Expression.Assign(body, c);
return Expression.Lambda<Action>(a);
}
with this, the code in the question is simply
ViewModelBase vm = new ViewModelBase();
vm.RunAndRaise(Assignment(() => vm.Value, 1));
If you change the definition like
public void RunAndRaise(Expression<Action> Exp) {
Exp.Compile()();
PropertyChanged(Exp.Member.Name);
}
We can also say
//Set the current thread name to "1234"
Assignment(() => Thread.CurrentThread.Name, "1234")).Compile()();
Simple enough, isn't it?
A general solution for the expression tree may not contain an assignment operator issue would be to create a local setter Action and call that one by the Expression:
// raises "An expression tree may not contain an assignment operator"
Expression<Action<string>> setterExpression1 = value => MyProperty = value;
// works
Action<string> setter = value => MyProperty = value;
Expression<Action<string>> setterExpression2 = value => setter(value);
This may not be suited to your exact problem, but I'm hoping this helps someone as this question is kind of the best match for googling that error message.
I'm unsure why exactly the compiler disallows this.
May be u mean Expression.Assign which was added in .net 4.0?

Expression tree - how to get at declaring instance?

I'm a newbie when it comes to expression trees, so I'm not sure how to ask this question or what terminology to use. Here's an overly-simplifed version of what I'm trying to do:
Bar bar = new Bar();
Zap(() => bar.Foo);
public static void Zap<T>(Expression<Func<T>> source)
{
// HELP HERE:
// I want to get the bar instance and call bar.Zim() or some other method.
}
How can I get to bar inside the Zap method?
Since the expression passed into your Zap method is a tree, you just need to walk the tree using an Expression Tree Visitor and look for the first ConstantExpression in the expression. It will likely be in the following sequence:
(((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value
Note that the bar instance is captured by a closure, which is implemented as an internal class with the instance as a member, which is where the 2nd MemberExpression comes from.
EDIT
Then you have to get the field from the generated closure like so:
static void Main(string[] args)
{
var bar = new Bar();
bar.Foo = "Hello, Zap";
Zap(() => bar.Foo);
}
private class Bar
{
public String Foo { get; set; }
}
public static void Zap<T>(Expression<Func<T>> source)
{
var param = (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value;
var type = param.GetType();
// Note that the C# compiler creates the field of the closure class
// with the name of local variable that was captured in Main()
var field = type.GetField("bar");
var bar = field.GetValue(param) as Bar;
Debug.Assert(bar != null);
Console.WriteLine(bar.Foo);
}
If you know the type of "bar", you can do this (I'm reusing some bits from the codekaizen's answer here):
static void Main(string[] args)
{
var bar = new Bar();
bar.Foo = "Hello, Zap";
Zap(() => bar.Foo);
Console.ReadLine();
}
private class Bar
{
public String Foo { get; set; }
}
public static void Zap<T>(Expression<Func<T>> source)
{
var body = source.Body as MemberExpression;
Bar test = Expression.Lambda<Func<Bar>>(body.Expression).Compile()();
Console.WriteLine(test.Foo);
}
In most cases, you can find an expression representing your object within an expression tree, and then compile and execute this expression and get the object (but this is not a very fast operation, by the way). So, the bit you were missing is the Compile() method. You can find a little bit more info here: How to: Execute Expression Trees.
In this code, I assume that you always pass an expression like "() => object.Member". For a real-world scenario you will need either to analyze that you have an expression you need (e.g. just throw an exception if it's not a MemberExpression). Or use ExpressionVisitor, which is kind of tricky.
I have recently answered a very similar question here:
How do I subscribe to an event of an object inside an expression tree?
Standing on the shoulders of giants above, my final extension method to extract the instance of the class that represented the source of the expression looks as follows:
public static TIn GetSource<TIn, TOut>(this Expression<Func<TIn, TOut>> property)
where TIn: class
{
MemberExpression memberExpression = (MemberExpression)property.Body;
TIn instance = Expression.Lambda<Func<TIn>>(memberExpression.Expression).Compile()();
return instance;
}
I built on all of the answers above, thanks to all.

Categories