2012-12-06 103 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