3 回答
TA贡献1818条经验 获得超3个赞
我们考虑过添加新的操作“?”。到具有您想要的语义的语言。(现在已添加;见下文。)也就是说,你会说
cake?.frosting?.berries?.loader
并且编译器会为您生成所有短路检查。
它没有成为C#4的标准。也许是对于该语言的假设未来版本。
更新(): 该?.
运营商正在计划在未来罗斯林编译器版本。请注意,对运算符的确切语法和语义分析仍存在争议。
更新(): Visual Studio 2015已经发布,并附带一个C#编译器,支持null条件运算符?.
和?[]
。
TA贡献1886条经验 获得超2个赞
我受到了这个问题的启发,试图找出如何使用表达式树更简单/更漂亮的语法来完成这种深度空值检查。虽然我同意答案,如果你经常需要访问层次结构中的深层实例,那么它可能是一个糟糕的设计,我也认为在某些情况下,例如数据表示,它可能非常有用。
所以我创建了一个扩展方法,允许你写:
var berries = cake.IfNotNull(c => c.Frosting.Berries);
如果表达式的任何部分都不为null,则返回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; } }}
它的工作原理是检查表达你的表达式的表达式树,并一个接一个地评估这些部分; 每次检查结果都不为空。
我确信这可以扩展,以便支持除MemberExpression之外的其他表达式。将其视为概念验证代码,请记住,使用它会导致性能下降(在许多情况下可能无关紧要,但不要在紧密循环中使用它:-))
TA贡献1816条经验 获得超6个赞
我发现这个扩展对于深度嵌套场景非常有用。
public static R Coal<T, R>(this T obj, Func<T, R> f) where T : class{ return obj != null ? f(obj) : default(R);}
这是我从C#和T-SQL中的空合并运算符中获得的一个想法。好处是返回类型始终是内部属性的返回类型。
这样你可以这样做:
var berries = cake.Coal(x => x.frosting).Coal(x => x.berries);
...或上述的略有变化:
var berries = cake.Coal(x => x.frosting, x => x.berries);
这不是我所知道的最好的语法,但确实有效。
- 3 回答
- 0 关注
- 483 浏览
添加回答
举报