如何从 ()=>foo.Title 表达式中获取对象实例 [英] How can I get object instance from ()=>foo.Title expression

查看:21
本文介绍了如何从 ()=>foo.Title 表达式中获取对象实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有属性的简单类

I have a simple class with a property

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

我试图通过调用类似的函数来简化数据绑定

I am trying to simplify data binding by calling a function like

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

声明如下

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

    control.DataBindings.Add("Text", ??? , name);
}

那么我在 ??? 中为我的 Foo 类的实例放了什么.如何从 lambda 表达式获得对调用 foo 实例的引用?

so what do I put in ??? for the instance of my Foo class. How do I get a refernce to the calling foo instance from the lambda expression?

该实例应该在某处,因为我可以调用 property.Compile() 并创建一个委托,该委托在我的 BindToText 函数中使用 foo 实例.所以我的问题是这是否可以在不添加对函数参数中的实例的引用的情况下完成.我呼吁 Occum's Razor 得出最简单的解决方案.

edit: The instance should be there somewhere because I can call property.Compile() and create a delegate that uses the foo instance inside my BindToText function. So my question is if this can be done without adding a reference to the instance in the function parameters. I call upon Occum's Razor to yield the simplest solution.

编辑 2:许多人没有注意到的是,如果我编译 lambda,在访问我的函数内的 foo 实例时存在的 closure.为什么编译器知道在哪里可以找到实例,而我不知道?我坚持认为必须有一个答案, 不必传递额外的参数.

edit 2: What many have failed to notice is the closure that exists in accessing the instance of foo inside my function, if I compile the lambda. How come the compiler knows where to find the instance, and I don't? I insist that there has to be an answer, without having to pass an extra argument.

感谢 VirtualBlackFox 解决方案是这样的:

Thanks to VirtualBlackFox the solution is such:

void BindText<T>(TextBoxBase text, Expression<Func<T>> property)
{
    var mex = property.Body as MemberExpression;
    string name = mex.Member.Name;
    var fex = mex.Expression as MemberExpression;
    var cex = fex.Expression as ConstantExpression;            
    var fld = fex.Member as FieldInfo;
    var x = fld.GetValue(cex.Value);
    text.DataBindings.Add("Text", x, name);            
}

这让我可以简单地输入 BindText(titleText, () => foo.Title);.

which alows me to simply type BindText(titleText, () => foo.Title);.

推荐答案

您想要的小型 LINQPad 示例:

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);
}

这篇关于如何从 ()=>foo.Title 表达式中获取对象实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆