zoukankan      html  css  js  c++  java
  • [小技巧]让C#的空值处理变得更优雅

    参考

    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;
            }
        }
    }
    
     
  • 相关阅读:
    树形DP 统计树中长度为K的路径数量——Distance in Tree
    Linux下使用Vi是方向键变乱码 退格键不能使用的解决方法
    wikioi 1029 中序遍历总数
    struts2前端页面读取Clob/BLOB
    hdu 1712 ACboy needs your help
    HDU 2489 Minimal Ratio Tree (dfs+Prim最小生成树)
    用XMLRPC开服务进行server/client通信
    HDU 1171 Big Event in HDU
    VS2012调试执行,网页打不开
    解决安装OpenShift Client Tools时提示的dl/import (LoadError)问题
  • 原文地址:https://www.cnblogs.com/caption/p/3966458.html
Copyright © 2011-2022 走看看