• C#中检查null的语法糖


    今天看到已经更新了devblogs,新增的C# 11的!!(用于检查null的语法)经过非常长的讨论,最后取消了。然后我又想起来null检查,这个可以说一说。

    函数参数null检查

    传统写法

    写一个函数的时候,最经典的检查,估计也是大家最常使用的null检查,应该是这样的吧:

    public static void GetV1(string prompt)
    {
        if (prompt is null) throw new ArgumentNullException(nameof(prompt));
        Console.WriteLine(prompt);
    }
    

    ThrowIfNull

    这个写起来也没啥问题,但是总觉得有点不舒适。.NET 6在ArgumentNullException中新增了ThrowIfNull方法,可以写的更优雅一点。

    public static void GetV2(string prompt)
    {
        ArgumentNullException.ThrowIfNull(prompt);
        Console.WriteLine(prompt);
    } 
    

    异常的时候,就会出现:System.ArgumentNullException: 'Value cannot be null. (Parameter 'prompt')'。这个是不是简单了点?可是还是需要写一行。

    C# 11的!!语法(已经取消)

    C# 11刚preview的时候,我就瞄到了这个特性,现在依然可以通过设置preview来进行启用,但是以后正式发布估计就不行了。

    它通过在参数后面叠加!!表示此参数不可为空,运行时会自动进行检查,如果是null就直接弹出错误。

    public static void GetV3(string prompt!!)
    {
        Console.WriteLine(prompt);
    }
    

    这个代码会被编译器翻译成:

    public static void GetV3(string prompt!!)
    {
        if (prompt is null) {
            throw new ArgumentNullException(nameof(prompt));
        }
        Console.WriteLine(prompt);
    }
    

    这样大家就可以专注于业务代码,不需要经常考虑异常检查了。至于为什么这个东西最后还是被删除了,可以从讨论中看到一丝端倪,首先是感觉非常纠结于这个语法,两个叹号;然后就是已经有比较多的方式可以实现检查了,这个东西是否有必要。反正最终是以后再讨论了,不过也可以看出来C#语言工作组对语言的特性讨论非常谨慎。

    他们还讨论了很多别的形式,每种都提出了各自的优缺点挺有意思的,能看出来有一点设计语言的严谨和小强迫症在,点赞~

    void M(string s!!);
    void M(string! s);
    void M(string s!);
    void M(notnull string s);
    void M(string s ?? throw);
    void M(string s is not null);
    void M(checked string s);
    void M(string s) where s is not null;
    

    有关null的一些操作

    说起这个,就顺便说说c#处理null的另外几个语法糖吧。

    ??

    如果左边是的null,那么返回右边的操作数,否则就返回左边的操作数,这个在给变量赋予默认值非常好用。

    int? a = null;
    int b = a ?? -1;
    Console.WriteLine(b);  // output: -1
    

    ??=

    当左边是null,那么就对左边的变量赋值成右边的

    int? a = null;
    a ??= -1;
    Console.WriteLine(a);  // output: -1
    

    ?.

    当左边是null,那么不执行后面的操作,直接返回空,否则就返回实际操作的值。

    using System;
    public class C {
        public static void Main() {
            string i = null;
            int? length = i?.Length;
            Console.WriteLine(length ?? -1); //output: -1
        }
    }
    

    ?[]

    索引器操作,和上面的操作类似

    using System;
    public class C {
        public static void Main() {
            string[] i = null;
            string result = i?[1];
            Console.WriteLine(result ?? "null"); // output:null
        }
    }
    

    注意,如果链式使用的过程中,只要前面运算中有一个是null,那么将直接返回null结果,不会继续计算。下面两个操作会有不同的结果。

    using System;
    public class C {
        public static void Main() {
            string[] i = null;
            Console.WriteLine(i?[1]?.Substring(0).Length); //不弹错误
            Console.WriteLine((i?[1]?.Substring(0)).Length) // System.NullReferenceException: Object reference not set to an instance of an object.
        }
    }
    

    一些操作

    //参数给予默认值
    if(x == null) x = "str";
    //替换
    x ??= "str";
    
    
    //条件判断
    string x;
    if(i<3) 
        x = y;
    else 
    {  
        if(z != null) x = z; 
        else z = "notnull";
    }
    //替换
    var x = i < 3 ? y : z ?? "notnull"
    
    
    //防止对象为null的时候,依然执行代码
    if(obj != null) 
        obj.Act();
    //替换
    obj?.Act();
    
    //Dictionary取值与赋值
    string result;
    if(dict.ContainKey(key))
    {
        if(dict[key] == null) result = "有结果为null";
        else result = dict[key];
    }
    else 
        result = "无结果为null";
    //替换
    var result= dict.TryGetValue(key, out var value) ? value ?? "有结果为null" : "无结果为null";
    

    结语

    原来新定的C# 11提供了一个新的??,话说我个人还是挺喜欢这个特性的,不管以什么形式出现吧,期待以后再见。

    C#中为了处理null给我们准备了许多的语法糖,只能说非常简便了。有很多人会说这个可读性不好,或者觉得这是“茴字的几种写法”似的歪门邪道,我只能说,传统的语法也不是说取消了,语言有发展,只要还是比较审慎的,我觉得还是一件好事。

    参考资料

    后记

    一定要夸一下博客园,写完这篇文章想登陆博客园发布的时候,被登陆卡住了。弹出来和google一样的验证画面,找红绿灯找人行横道什么的,只能说我找了几分钟也没找明白,我确信我已经点的正确了,所有的区块,占上了有一点算不算?不知道也没有反馈,就点呀点呀,密码我已经按照要求设置的够复杂了,还有必要通过这种反人类的东西来验证吗?不理解,京东阿里之类的购物网站的验证也就拖一下完事,这博客园的后台估计比那些个地方还要敏感吧,赞一个!太赞了!

  • 相关阅读:
    在C#程序中模拟发送键盘按键消息
    C# UDPCLIENT多线程实例
    【转】WINFORM下FTP客户端的实现
    抓取屏幕或窗体并保存成图片
    c# 判断窗体已打开则显示为焦点
    【转】C#中dataGridView用法实例分析
    【转】VC6控件小记
    .Net部署二三事之一——如何为VS安装文件MSI制作更新补丁MSP
    [转]C#串口serialPort操作
    VS向IIS发布C#或VB应用程序
  • 原文地址:https://www.cnblogs.com/podolski/p/16184027.html
Copyright © 2020-2023  润新知