我有一個帶有屬性的簡單類
class Foo
{
string Title { get; set; }
}
我試圖通過調用類似的函數來簡化數據綁定
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
實例的引用?
編輯:該實例應該在某個地方,因為我可以調用property.Compile()
並創建一個在我的BindToText
函數中使用foo
實例的委託。所以我的問題是,是否可以在函數參數中不添加對實例的引用的情況下完成此操作。我呼籲Occum的Razor提供最簡單的解決方案。
編輯2:許多人沒有註意到的是,如果我編譯lambda,則在訪問函數中的foo
實例時存在閉包 。編譯器怎麼知道在哪裡可以找到實例,而我卻不知道呢?我堅持必須有一個答案, 而不必通過額外的爭論。
感謝VirtualBlackFox ,解決方案是這樣的:
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);
。
您想要的小LINQPad樣本:
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);
}
別。只需修改方法以獲取另一個參數,如#3444294中所述 。對於您的示例,它可能是這樣的:
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);
}
並會被稱為
BindToText(titleTextBox, foo, ()=>foo.Title );
還不錯,但很容易理解。沒有魔法發生。 ;)