如何从()=> foo.Title表达式获取对象实例
我有一个带有属性的简单类
class Foo { string Title { get; set; } }
我试图通过调用函数来简化数据绑定
BindToText(titleTextBox, ()=>foo.Title );
这被宣布为
void BindToText(Control control, Expression<Func> property) { var mex = property.Body as MemberExpression; string name = mex.Member.Name; control.DataBindings.Add("Text", ??? , name); }
那我该怎么办???
对于我的Foo
类的实例。 如何从lambda表达式中获取对调用foo
实例的引用?
编辑:实例应该在某处,因为我可以调用property.Compile()
并创建一个在我的BindToText
函数中使用foo
实例的委托。 所以我的问题是,如果可以在不添加函数参数中实例的引用的情况下完成此操作。 我呼吁Occum的Razor提供最简单的解决方案。
编辑2:许多人没有注意到的是在我的函数中访问foo
实例时存在的闭包 ,如果我编译lambda。 为什么编译器知道在哪里找到实例,我不知道? 我坚持认为必须有一个答案, 而不必通过额外的论证。
解
感谢VirtualBlackFox的解决方案是这样的:
void BindText(TextBoxBase text, Expression<Func> 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);
。
您想要的小LINQPad样本:
void Foo(Expression> 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); }
别。 只需修改方法以获取另一个参数,如#3444294中所述 。 对于您的示例,它可能是这样的:
void BindToText(Control control, T dataSource, Expression> property) { var mex = property.Body as MemberExpression; string name = mex.Member.Name; control.DataBindings.Add("Text", dataSource, name); }
并会被称为
BindToText(titleTextBox, foo, ()=>foo.Title );
还不错,但很容易理解。 没有魔法发生。 ;)
像下面这样的东西应该工作:
void BindToText(Control control, Expression> 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); }
如果这对您不起作用,请告诉我。