参考
http://www.codePRoject.com/Articles/739772/Dynamically-Check-Nested-Values-for-IsNull-Values?msg=4895299#xx4895299xx
http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/
介绍
C#中的空值处理,一直是一件比较让人不爽的工作。假设现在有如下类:
public class Union { public string Name { get; set; } } public class Dep { public Union Union { get; set; } public string Name { get; set; } } public class Person { public Dep Dep { get;set;} public string Name { get; set; } }
如果Person.Dep.Union.Name.Length>5,则写入日志,代码该怎么写呢?很可能是这样:
if (person != null && person.Dep != null && person.Dep.Union != null && person.Dep.Union.Name != null && person.Dep.Union.Name.Length > 5) { Console.WriteLine(person.Dep.Union.Name); }
逻辑语句写得多的各位,对于这样写的繁琐应该深有体会。
对策
1扩展方法在访问对象前,会先进入其对应的静态方法。可以很方便的对this参数进行判断和处理,而不引起nullreference异常;
2委托可以很好的进行扩展方法的后续动作。
我们可以这样写上面的语句
person .GoTo(p => p.Dep.Union.Name) .If(n => n.Length >= 5) .Do(Console.WriteLine);
很简洁,是不是?怎么实现呢?只需加入下列扩展类:
using System;using System.Linq;using System.Linq.Expressions;using System.Reflection;namespace LinqTesting{ public static class Helper { class IsNullVisitor : ExpressionVisitor { public bool IsNull { get; private set; } public object CurrentObject { get; set; } protected override Expression VisitMember(MemberExpression node) { //it will call this overrided method with higher level node base.VisitMember(node); if (CheckNull()) return node; var member = (PropertyInfo)node.Member; CurrentObject = member.GetValue(CurrentObject, null); CheckNull(); return node; } private bool CheckNull() { if (CurrentObject == null) IsNull = true; return IsNull; } } public static TReturn GoTo<T, TReturn>(this T root, Expression<Func<T, TReturn>> funcGetValue) { var visitor = new IsNullVisitor(); visitor.CurrentObject = root; visitor.Visit(funcGetValue); if (visitor.IsNull) return default(TReturn); return (TReturn)visitor.CurrentObject; } public static TInput If<TInput>(this TInput o, Func<TInput, bool> evaluator) where TInput : class { if (o == null) return null; return evaluator(o) ? o : null; } public static TInput Unless<TInput>(this TInput o, Func<TInput, bool> evaluator) where TInput : class { if (o == null) return null; return evaluator(o) ? null : o; } public static TInput Do<TInput>(this TInput o, Action<TInput> action) where TInput : class { if (o == null) return null; action(o); return o; } }}
新闻热点
疑难解答