[小技巧]让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;

        }

    }

}

 

 

你可能感兴趣的:(小技巧)