字符串拼接这个隐藏大坑,我表示不服~

博客 动态
0 172
羽尘
羽尘 2022-05-13 23:59:13
悬赏:0 积分 收藏

字符串拼接这个隐藏大坑,我表示不服~

前言

先看写个简单的代码,看看你能不能答对

// See https://aka.ms/new-console-template for more informationConsole.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的情况,但是可能同时为nullvar resMsg = (context.Error + context.ErrorDes) ?? "系统异常"

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

思考

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

posted @ 2022-05-13 23:20 gui.h 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员