深度零检查,有更好的方法吗?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (22)

我们都在那里,我们有一些深层次的属性,比如cake.Frosting.berries.Loader,我们需要检查它是否为NULL,所以也没有例外。方法是使用短路if语句。

if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...

这并不是很优雅,也许应该有一种更简单的方法来检查整个链,看看它是否遇到了空变量/属性。

是否可以使用某种扩展方法,或者它是一种语言特性,还是一个糟糕的想法?

提问于
用户回答回答于

cake?.frosting?.berries?.loader

编译器会为你生成所有的短路检查。

更新(2014):?.操作员现在用于下一个Roslyn编译器发行版。请注意,对于操作符的确切句法和语义分析,仍有一些争论。

更新(2015):VisualStudio 2015已经发布,并附带了一个C#编译器。

用户回答回答于

我创建了一个扩展方法,它允许编写:

var berries = cake.IfNotNull(c => c.Frosting.Berries);

这将返回浆果,如果表达式的任何部分为空。如果遇到NULL,则返回NULL。但是,在当前版本中,它只适用于简单的成员访问,并且只在.NET Framework 4上工作,因为它使用MemberExpression.Update方法,这在v4中是新的。这是IfNotNull扩展方法的代码:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace dr.IfNotNullOperator.PoC
{
    public static class ObjectExtensions
    {
        public static TResult IfNotNull<TArg,TResult>(this TArg arg, Expression<Func<TArg,TResult>> expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            if (ReferenceEquals(arg, null))
                return default(TResult);

            var stack = new Stack<MemberExpression>();
            var expr = expression.Body as MemberExpression;
            while(expr != null)
            {
                stack.Push(expr);
                expr = expr.Expression as MemberExpression;
            } 

            if (stack.Count == 0 || !(stack.Peek().Expression is ParameterExpression))
                throw new ApplicationException(String.Format("The expression '{0}' contains unsupported constructs.",
                                                             expression));

            object a = arg;
            while(stack.Count > 0)
            {
                expr = stack.Pop();
                var p = expr.Expression as ParameterExpression;
                if (p == null)
                {
                    p = Expression.Parameter(a.GetType(), "x");
                    expr = expr.Update(p);
                }
                var lambda = Expression.Lambda(expr, p);
                Delegate t = lambda.Compile();                
                a = t.DynamicInvoke(a);
                if (ReferenceEquals(a, null))
                    return default(TResult);
            }

            return (TResult)a;            
        }
    }
}

它的工作方式是检查表示表达式的表达式树,并逐个计算各个部分;每次检查结果是否为NULL。

扫码关注云+社区