參考
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; } }}新聞熱點
疑難解答