2016-01-06 20 views
0

使用C#6,我们可以使用新的?来访问属性和方法,而不必检查每个属性是否为null。是否可以使用表达式编写一个具有siliar功能的方法?如何创建一个具有与新“?”类似的功能的方法。运营商?

例如,我必须使用一个奇怪的对象结构(来自第三方库,我们不能改变)。访问某些属性,需要经常长点的链:

rootObject.Services.First().Segments.First().AnotherCollection.First().Weight; 

任何对象后rootObject可以null。我宁愿不要把try/catch围绕它。还分别检查每个属性是很多工作。所以我在想,如果我可以把它传递给方法取一个表达式并遍历每个属性,并有检查其值:

var value = PropertyHelper.GetValue(() => rootObject.Services.First().Segments.First().AnotherCollection.First().Weight); 

我想它的签名会是这样的:

public static T GetValue<T>(Expression<Func<T>> expression) 
{ 
    // analyze the expression and evaluate each property/method 
    // stop when null or return the value 
} 

我我不确定表情是否能够做我将要做的事情,在我开始尝试之前,我想问问它是否有可能。

+0

有一个原因,他们作为一个操作员添加它。这是*可能*,但比使用C#6的操作员要笨得多。在处理C#操作符能够解决的不可空类型时也存在问题(并且您无法解决)。 – Servy

+0

那么,你可以创建(子类)一个'ExpressionVisitor'来检查成员访问,调用等,并注入(重写表达式)检查,但是..这是很多反思和大量访问,并且那么你需要'编译()'它(添加元编程)或者添加*更多*反射来评估树在运行时......看起来很多开销 –

+0

@MarcGravell真,尽管如果问题代码isn在应用程序的性能特别敏感的部分中,并且不是频繁调用,或者编译的委托可以被重用,则性能可能不足以排除该解决方案。 – Servy

回答

2
void Main() 
{ 
    var foo = new Foo(); 

    var qux = NullPropertyExtension.GetValue(() => foo.Bar.Qux); 

    Console.WriteLine(qux); 


} 

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

// Define other methods and classes here 
public static class NullPropertyExtension 
{ 
    public static TValue GetValue<TValue>(Expression<Func<TValue>> property) 
    { 
     var visitor = new Visitor(); 
     var expression = visitor.Visit(property.Body); 
     var lambda = Expression.Lambda<Func<TValue>>(expression); 

     var func = lambda.Compile(); 
     return func(); 
    } 

    private class Visitor : System.Linq.Expressions.ExpressionVisitor 
    { 
     protected override Expression VisitMember(MemberExpression node) 
     { 
      var isNotNull = Expression.NotEqual(node.Expression, Expression.Constant(null)); 
      return Expression.Condition(
       isNotNull, 
       node, 
       Expression.Constant(null, node.Type)); 

     } 
    } 
} 
+0

哇,简单或简短;-)但对我来说仍然很神奇。我需要研究它。谢谢。 – t3chb0t

+0

@ t3chb0t注意:这个类仅仅处理一个对象的空值,你试图从中获取一个属性/字段。对于'.First()'工作,你需要重写'VisitCallMethod'方法(注意静态方法)。 – Aron

+0

甚至有'null'作为参数的方法是ligit。 – Aron