字符串拼接这个隐藏大坑,我表示不服~ - gui.h
source link: https://www.cnblogs.com/springhgui/p/16268681.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
字符串拼接这个隐藏大坑,我表示不服~ - gui.h - 博客园
先看写个简单的代码,看看你能不能答对
// 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.Error
和context.ErrorDes
虽然均为null
,但是他们的结果不是null
,最终resMsg
是""
,害~~~
虽然我们知道为啥是string.Empty
了,但是还是觉得null
才更加合理,不知道设计者是出于什么考虑,如果你知道,请告诉我,如果本文对你有帮助,请点赞,关注,转发,支持一波~
__EOF__
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK