2012-12-06 144 views
4

我正在研究一些代碼,它的最終目的是讓您使用屬性表達式來設置屬性的值,該屬性的語法類似於將變量傳遞爲out或ref參數。從屬性表達式獲取屬性的擁有對象

東西線沿線的:

public static foo(()=>Object.property, value); 

而且Object.Property將被賦予價值的價值。

我用下面的代碼來獲取財產的owining對象:

public static object GetOwningObject<T>(this Expression<Func<T>> @this) 
    { 
     var memberExpression = @this.Body as MemberExpression; 
     if (memberExpression != null) 
     { 
      var fieldExpression = memberExpression.Expression as MemberExpression; 
      if (fieldExpression != null) 
      { 
       var constExpression = fieldExpression.Expression as ConstantExpression; 
       var field = fieldExpression.Member as FieldInfo; 
       if (constExpression != null) if (field != null) return field.GetValue(constExpression.Value); 
      } 
     } 
     return null; 
    } 

所以這會,就像一個屬性表達式()=> Object.Property使用時,回饋的實例'對象'。我在使用屬性表達式方面有點新,而且似乎有許多不同的方法來完成工作,但我想擴展到目前爲止的所有內容,以便給出諸如()=> Foo.Bar.Baz之類的表達式會給酒吧,而不是Foo。我總是希望表達式中的最後一個包含對象。

任何想法?提前致謝。

回答

1

你必須做的是遍歷財產鏈到最外面的對象。 下面的示例是相當自我解釋,並表明該擴展方法會爲鏈領域的工作,以及屬性:

class Foo 
{ 
    public Bar Bar { get; set; } 
} 

class Bar 
{ 
    public string Baz { get; set; } 
} 

class FooWithField 
{ 
    public BarWithField BarField; 
} 

class BarWithField 
{ 
    public string BazField; 
} 

public static class LambdaExtensions 
{ 
    public static object GetRootObject<T>(this Expression<Func<T>> expression) 
    { 
     var propertyAccessExpression = expression.Body as MemberExpression; 
     if (propertyAccessExpression == null) 
      return null; 

     //go up through property/field chain 
     while (propertyAccessExpression.Expression is MemberExpression) 
      propertyAccessExpression = (MemberExpression)propertyAccessExpression.Expression; 

     //the last expression suppose to be a constant expression referring to captured variable ... 
     var rootObjectConstantExpression = propertyAccessExpression.Expression as ConstantExpression; 
     if (rootObjectConstantExpression == null) 
      return null; 

     //... which is stored in a field of generated class that holds all captured variables. 
     var fieldInfo = propertyAccessExpression.Member as FieldInfo; 
     if (fieldInfo != null) 
      return fieldInfo.GetValue(rootObjectConstantExpression.Value); 

     return null; 
    } 
} 

[TestFixture] 
public class Program 
{ 
    [Test] 
    public void Should_find_root_element_by_property_chain() 
    { 
     var foo = new Foo { Bar = new Bar { Baz = "text" } }; 
     Expression<Func<string>> expression =() => foo.Bar.Baz; 
     Assert.That(expression.GetRootObject(), Is.SameAs(foo)); 
    } 

    [Test] 
    public void Should_find_root_element_by_field_chain() 
    { 
     var foo = new FooWithField { BarField = new BarWithField { BazField = "text" } }; 
     Expression<Func<string>> expression =() => foo.BarField.BazField; 
     Assert.That(expression.GetRootObject(), Is.SameAs(foo)); 
    } 
} 
+0

對不起,我這些年以前錯過了!我會試試這個,但是這段代碼早已不復存在,但對我來說似乎很好。 – Brandorf