搜索
简帛阁>技术文章>字符串拼接这个隐藏大坑,我表示不服~

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

前言

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

// 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:异常

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

答案

不墨迹,直接运行代码看结果:

很明显答案是 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才更加合理,不知道设计者是出于什么考虑,如果你知道,请告诉我,如果本文对你有帮助,请点赞,关注,转发,支持一波~

前言先看写个简单的代码,看看你能不能答对//Seehttps://akams/newconsoletemplateformoreinformationConsoleWriteLine(Hello,Wo
久没维护《吊打面试官》系列了,今天再来一篇,这次真的要吊打了,哈哈!(看往期吊打系列请在后台回复:吊打,会陆续更新……)我们做Java程序员以来,不管是工作当中,还是面试过程中,都知道:字符串拼接
include<iostream>include<Windowsh>usingnamespacestd;intmain(){charMAC[215]wwwbaidu;charD
题意在x,y坐标系,有流星会落下来,给出每颗流星落下来的坐标和时间,问你能否从(0,0)这个点到一个安全的位置。所谓的安全位置就是不会有流星落下的位置。题解:广搜,但是这里有一个深坑,就是搜索的时候判
模板:intmin_max_express(char*s,intlen,boolflag){//最小表示法和最大表示法写到一块儿了inti0,j1,k0;while(i<lenj<lenk
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串+100,5e2,123,31416和1E16都表示数值。但是12e,1a314,123,+5和12e+43都不是。publi
述基本概念(字符)串(string)是指由零个或者多个元素(字符)组成的有限的序列。序列中所含的字符的个数称为该串的长度(教材中讨论的都是基于ASCII编码的字符串的长度,这里不讨论Unicode、
【1】需求(11)列与列(A2B2)A2B2(12)列与常规字符串与列(j2("@")k2)j2("@")k2所以常量,字符串就都是需要用括号双引号》("")包裹起来;单引号也是如此("'")
代码如下:@echooff::每6行拼接为一行,剩余的不够6行的显示在最后一行::::setnum0setlocalenabledelayedexpansionfor/f"delims"%%iin(a
常用拼接方法字符串拼接在日常开发中是很常见的需求,目前有两种普遍做法:一种是直接用+来拼接s1:Hellos2:Worlds3:s1+s2//s3HelloWorlds1+s2//s1HelloWo