How can I get object instance from ()=>foo.Title expression

前端 未结 4 1351
感动是毒
感动是毒 2020-12-13 10:05

I have a simple class with a property

class Foo 
{ 
    string Title { get; set; } 
}

I am trying to simplify data binding by calling a fun

相关标签:
4条回答
  • 2020-12-13 10:12

    Small LINQPad sample of what you want :

    void Foo<T>(Expression<Func<T>> prop)
    {
        var propertyGetExpression = prop.Body as MemberExpression;
    
        // Display the property you are accessing, here "Height"
        propertyGetExpression.Member.Name.Dump();
    
        // "s" is replaced by a field access on a compiler-generated class from the closure
        var fieldOnClosureExpression = propertyGetExpression.Expression as MemberExpression;
    
        // Find the compiler-generated class
        var closureClassExpression = fieldOnClosureExpression.Expression as ConstantExpression;
        var closureClassInstance = closureClassExpression.Value;
    
        // Find the field value, in this case it's a reference to the "s" variable
        var closureFieldInfo = fieldOnClosureExpression.Member as FieldInfo;
        var closureFieldValue = closureFieldInfo.GetValue(closureClassInstance);
    
        closureFieldValue.Dump();
    
        // We know that the Expression is a property access so we get the PropertyInfo instance
        // And even access the value (yes compiling the expression would have been simpler :D)
        var propertyInfo = propertyGetExpression.Member as PropertyInfo;
        var propertyValue = propertyInfo.GetValue(closureFieldValue, null);
        propertyValue.Dump();
    }
    
    void Main()
    {
        string s = "Hello world";
        Foo(() => s.Length);
    }
    
    0 讨论(0)
  • 2020-12-13 10:14

    Well, this is similar in tone to Hangy's solution, but is I think rather comfortable to use and does not require much magic:

    public static Binding CreateTextBinding<T>(this T source, Expression<Func<T,object>> access)
    {
        var mex = access.Body as MemberExpression;
        string name = mex.Member.Name;
        return new Binding("Text", source, name);
    }
    

    This is basically an extension method that can be called on any object acting as source. It gives you back a Binding for a Text property which you can add to any Bindings collection.

    0 讨论(0)
  • 2020-12-13 10:31

    Something like the following should work:

    void BindToText<T>(Control control, Expression<Func<T>> property)
    {
        var mex = property.Body as MemberExpression;
        string name = mex.Member.Name;
    
        var fooMember = mex.Expression as MemberExpression;
        var fooConstant = fooMember.Expression as ConstantExpression;
        var foo = fooConstant.Value;
    
        control.DataBindings.Add("Text", foo, name);
    }
    

    Let me know if that doesn't work for you.

    0 讨论(0)
  • 2020-12-13 10:33

    Don't. Just modify the method to take another parameter, as described in #3444294. For your example, it may be something like this:

    void BindToText<T>(Control control, T dataSource, Expression<Func<T>> property)
    {
        var mex = property.Body as MemberExpression;
        string name = mex.Member.Name;
    
        control.DataBindings.Add("Text", dataSource, name);
    }
    

    and would be called like

    BindToText(titleTextBox, foo, ()=>foo.Title );
    

    Still nice, but easy to understand. There's no magic happening. ;)

    0 讨论(0)
提交回复
热议问题