? 优质资源分享 ?
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
? Python实战微信订餐小程序 ? | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
?Python量化交易实战? | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
前言
先看写个简单的代码,看看你能不能答对
// 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 '$' (
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::'$'
主要看上面用注释标记的那行
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__
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-do3SGhVR-1652462007665)(https://blog.csdn.net/springhgui)]Gui.H - 本文链接: https://blog.csdn.net/springhgui/p/16268681.html
转载请注明:xuhss » 字符串拼接这个隐藏大坑,我表示不服~