• 字符串拼接你真的啥都知道了吗


    前言

    先看简单的题目,看看你能不能答对

    // See https://aka.ms/new-console-template for more information
    Console.WriteLine("Hello, World!");
    string v1 = null;
    string v2 = null;
    
    var v3 = v1 + v2;
    
    Console.WriteLine();
    

    请问上面这段代码v3的值是什么?

    A:null

    B:string.Empty

    C:异常

    请读者好好思考一下再往下看~

    答案

    不墨迹,直接运行代码看结果:
    image.png
    很明显答案是 B,此时你会不会有疑问:两个null相加,怎么会是""?我也有这个疑问,而且怎么都想不明白为什么~~~

    解惑

    将上面的代码编译后,使用ILSpy反编译工具查看IL中间语言代码看看,如下:

    .method private hidebysig static 
        void '<Main>$' (
            string[] args
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Header size: 12
        // Code size: 30 (0x1e)
        .maxstack 2
        .entrypoint
        .locals init (
            [0] string v1,
            [1] string v2,
            [2] string v3
        )
    
        // Console.WriteLine("Hello, World!");
        IL_0000: ldstr "Hello, World!"
        IL_0005: call void [System.Console]System.Console::WriteLine(string)
        // string text = null;
        IL_000a: nop
        IL_000b: ldnull
        IL_000c: stloc.0
        // string text2 = null;
        IL_000d: ldnull
        IL_000e: stloc.1
        // string text3 = text + text2;
        IL_000f: ldloc.0
        IL_0010: ldloc.1
        //++++++++++++++++++++++注意这一行++++++++++++++++++++++++++++
        IL_0011: call string [System.Runtime]System.String::Concat(string, string)
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        IL_0016: stloc.2
        // Console.WriteLine();
        IL_0017: call void [System.Console]System.Console::WriteLine()
        // }
        IL_001c: nop
        IL_001d: ret
    } // end of method Program::'<Main>$'
    

    主要看上面用注释标记的那行

    IL_0011: call string [System.Runtime]System.String::Concat(string, string)
    

    由此可以知道我们的两个变量相加,其实底层调用的是String::Concat(string, string)方法,从github上拉取dotnet/runtime仓库源码,找到string类型的源代码Concat(string, string)方法。

    public static string Concat(string? str0, string? str1)
    {
        // 第一个参数为空
        if (IsNullOrEmpty(str0))
        {
            // 第二个参数也为空
            if (IsNullOrEmpty(str1))
            {
                // 返回string.Empty
                return string.Empty;
            }
            return str1;
        }
    
        if (IsNullOrEmpty(str1))
        {
            return str0;
        }
    
        int str0Length = str0.Length;
    
        string result = FastAllocateString(str0Length + str1.Length);
    
        FillStringChecked(result, 0, str0);
        FillStringChecked(result, str0Length, str1);
    
        return result;
    }
    

    源码很简单,一上来就找到了返回string.Empty的结果,至此我们知道它为什么结果是string.Empty

    大坑

    之所以写本文,确实是实际项目中因为两个null字符串相加与我想想的不一样,出现bug,项目中的代码大概是这样的:

    // context.Error和context.ErrorDes均为string类型,
    // 两者绝不会存在为string.Empty的情况,但是可能同时为null
    var resMsg = (context.Error + context.ErrorDes) ?? "系统异常"
    

    本以为上面这段代码本意是想拼接两个错误信息输出,如果两个错误信息都是null,那么就返回系统异常,结果可想而知,context.Errorcontext.ErrorDes虽然均为null,但是他们的结果不是null,最终resMsg"",害~~~

    思考

    虽然我们知道为啥是string.Empty了,但是还是觉得null才更加合理,不知道设计者是出于什么考虑,如果你知道,请告诉我,如果本文对你有帮助,请点赞,关注,转发,支持一波~


    __EOF__

  • 本文作者: Gui.H
  • 本文链接: https://www.cnblogs.com/springhgui/p/16268681.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    机器学习第八课--决策树
    计算机毕设(附源码)JAVA-SSM基于中职学校的校医务室管理系统
    Android 9.0 屏蔽设备的WLAN功能
    Java 新手入门:基础知识点一览
    计算机图像处理:椒盐噪声和高斯噪声
    JVM垃圾回收机制
    python中datetime和time的区别,我学了一周整理的
    【进阶版】机器学习之EM经典算法原理+代码(11)
    拓展3: Python Xpath表达式的使用
    基于广义正态分布优化的BP神经网络(分类应用) - 附代码
  • 原文地址:https://www.cnblogs.com/springhgui/p/16268681.html