C#判断字符串是否为空的三种方法及其比较
2008-11-28 11:20
856 查看
1.最普遍、最直接的方法
string Input = "Yours Input Msg";
if (Input == "")
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr ""
IL_000d: call bool [mscorlib]System.String::op_Equality(string,string)
2.使用String.Empty
string Input = "Yours Input Msg";
if (Input == String.Empty)
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldsfld string [mscorlib]System.String::Empty
IL_000d: call bool [mscorlib]System.String::op_Equality(string,string)
3.使用string.Length
string Input = "Yours Input Msg";
if (Input.Length == 0)
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance int32 [mscorlib]System.String::get_Length()
在看过了三种方法之后,我们从底层开始进行比较,这里先做个假设,我们假设所有的单个IL语句执行时间相等,单位为1。(其实还是有差异的,但并不影响我们作比较。)
我们先反汇编mscorlib.dll得到System.String::op_Equality(strin,string):
.method public hidebysig specialname static
bool op_Equality(string a,
string b) cil managed
{
// 代码大小 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call bool System.String::Equals(string,
string)
IL_0007: ret
} // end of method String::op_Equality
发现他还要调用这个函数System.String::Equals(strin,string):
.method public hidebysig virtual instance bool
Equals(object obj) cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency,
valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 01 00 00 00 00 00 )
// 代码大小 23 (0x17)
.maxstack 2
.locals init (string V_0)
IL_0000: ldarg.1
IL_0001: isinst System.String
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_000f
IL_000a: ldarg.0
IL_000b: brfalse.s IL_000f
IL_000d: ldc.i4.0
IL_000e: ret
IL_000f: ldarg.0
IL_0010: ldloc.0
IL_0011: call bool System.String::EqualsHelper(string,
string)
IL_0016: ret
} // end of method String::Equals
然后还要调用System.String::EqualsHelper([b]string[/b],string):
.method private hidebysig static bool EqualsHelper(string strA,
string strB) cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency,
valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 01 00 00 00 00 00 )
// 代码大小 187 (0xbb)
.maxstack 3
.locals init (int32 V_0,
char* V_1,
char* V_2,
char* V_3,
char* V_4,
bool V_5,
string pinned V_6,
string pinned V_7)
IL_0000: ldarg.0
IL_0001: callvirt instance int32 System.String::get_Length()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.1
IL_0009: callvirt instance int32 System.String::get_Length()
IL_000e: beq.s IL_0012
IL_0010: ldc.i4.0
IL_0011: ret
IL_0012: ldarg.0
IL_0013: stloc.s V_6
IL_0015: ldloc.s V_6
IL_0017: conv.i
IL_0018: dup
IL_0019: brfalse.s IL_0021
IL_001b: call int32 System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0020: add
IL_0021: stloc.1
IL_0022: ldarg.1
IL_0023: stloc.s V_7
IL_0025: ldloc.s V_7
IL_0027: conv.i
IL_0028: dup
IL_0029: brfalse.s IL_0031
IL_002b: call int32 System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0030: add
IL_0031: stloc.2
IL_0032: ldloc.1
IL_0033: stloc.3
IL_0034: ldloc.2
IL_0035: stloc.s V_4
IL_0037: br.s IL_008b
IL_0039: ldloc.3
IL_003a: ldind.i4
IL_003b: ldloc.s V_4
IL_003d: ldind.i4
IL_003e: bne.un.s IL_00a9
IL_0040: ldloc.3
IL_0041: ldc.i4.4
IL_0042: conv.i
IL_0043: add
IL_0044: ldind.i4
IL_0045: ldloc.s V_4
IL_0047: ldc.i4.4
IL_0048: conv.i
IL_0049: add
IL_004a: ldind.i4
IL_004b: bne.un.s IL_00a9
IL_004d: ldloc.3
IL_004e: ldc.i4.8
IL_004f: conv.i
IL_0050: add
IL_0051: ldind.i4
IL_0052: ldloc.s V_4
IL_0054: ldc.i4.8
IL_0055: conv.i
IL_0056: add
IL_0057: ldind.i4
IL_0058: bne.un.s IL_00a9
IL_005a: ldloc.3
IL_005b: ldc.i4.s 12
IL_005d: conv.i
IL_005e: add
IL_005f: ldind.i4
IL_0060: ldloc.s V_4
IL_0062: ldc.i4.s 12
IL_0064: conv.i
IL_0065: add
IL_0066: ldind.i4
IL_0067: bne.un.s IL_00a9
IL_0069: ldloc.3
IL_006a: ldc.i4.s 16
IL_006c: conv.i
IL_006d: add
IL_006e: ldind.i4
IL_006f: ldloc.s V_4
IL_0071: ldc.i4.s 16
IL_0073: conv.i
IL_0074: add
IL_0075: ldind.i4
IL_0076: bne.un.s IL_00a9
IL_0078: ldloc.3
IL_0079: ldc.i4.s 20
IL_007b: conv.i
IL_007c: add
IL_007d: stloc.3
IL_007e: ldloc.s V_4
IL_0080: ldc.i4.s 20
IL_0082: conv.i
IL_0083: add
IL_0084: stloc.s V_4
IL_0086: ldloc.0
IL_0087: ldc.i4.s 10
IL_0089: sub
IL_008a: stloc.0
IL_008b: ldloc.0
IL_008c: ldc.i4.s 10
IL_008e: bge.s IL_0039
IL_0090: br.s IL_00a9
IL_0092: ldloc.3
IL_0093: ldind.i4
IL_0094: ldloc.s V_4
IL_0096: ldind.i4
IL_0097: bne.un.s IL_00ad
IL_0099: ldloc.3
IL_009a: ldc.i4.4
IL_009b: conv.i
IL_009c: add
IL_009d: stloc.3
IL_009e: ldloc.s V_4
IL_00a0: ldc.i4.4
IL_00a1: conv.i
IL_00a2: add
IL_00a3: stloc.s V_4
IL_00a5: ldloc.0
IL_00a6: ldc.i4.2
IL_00a7: sub
IL_00a8: stloc.0
IL_00a9: ldloc.0
IL_00aa: ldc.i4.0
IL_00ab: bgt.s IL_0092
IL_00ad: ldloc.0
IL_00ae: ldc.i4.0
IL_00af: cgt
IL_00b1: ldc.i4.0
IL_00b2: ceq
IL_00b4: stloc.s V_5
IL_00b6: leave.s IL_00b8
IL_00b8: ldloc.s V_5
IL_00ba: ret
} // end of method String::EqualsHelper
粗略估算了下,System.String::op_Equality(strin,string)执行时间大概是160。
这样方法1的大概运行时间是165,空间大概是220字节。方法2比只多了一次调用System.String::Empty(程序中的静态变量)
.field public static initonly string Empty
因此运行运行时间基本同方法1一致,空间上节省了2字节(原因是方法1需要先建立一个string类型("")后,再进行判断),可以忽略不计。很多文章谈到C#判断空字符串不同方法性能的时候往往以此为据,而看过上面的IL之后,我却不这么认为,真正的性能差异体现在了System.String::op_Equality(string,string)和System.String::get_Length()这两个函数之上。
下面我们看一下System.String::get_Length():
.method public hidebysig specialname instance int32
get_Length() cil managed internalcall
{
} // end of method String::get_Length
这个函数的函数体居然是空的?为什么?那难道这个不起作用吗?我认为是cil managed internalcall这个起了作用,取得字符串(内存中一块连续的区域)长度是非常快的,可以由CPU直接完成(这个是我的猜测,目前关于internalcall我们仅仅知道internalcall在RuntimeType类里面则是很容易就能够找到,速度很快,性能很高,这个可能涉及到程序的编译原理,不懂~~~)
反正这个函数很快很快就是了,那么方法3的运行时间大概只有6,空间大概是20多。
这样,我们得到了一个令人吃惊的结论,方法3在时间上只有前两种方法的约1/28,空间约是1/9。
为什么这样,我也不明白,我希望高手来指出我叙述或者论证不当的地方。
那么我们是否可以就直接使用方法3了呢?
答案是否定的。在C#使用属性时一定要注意异常捕捉的问题。
String的Length属性返回此实例中Char对象的个数,在C#中字符串可以看成是由多个Char组成的字符数组,这样如果String为null的话问题就来了,当String置为null时,相当于一个没有实例化的字符串数组,用Length取一个没有实例化数组的长度,那么产生异常就在所难免了。
因此应该这么做:
string Input = "Yours Input Msg";
if (Input!=null && Input.Length==0)
;
看一下IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0018
IL_000a: ldloc.0
IL_000b: callvirt instance int32 [mscorlib]System.String::get_Length()
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: ldc.i4.0
IL_0014: ceq
IL_0016: br.s IL_0019
运行时间大概是在5-13,空间越是30字节。这样,比起Input == ""这个方法,效率大约提高
13-30多倍(因为有短路运算),空间却只要1/7。
因此这些方法中判断字符串是否为空的最佳方法是:
desStr!=null && desStr.Length==0
本人初涉C#,很多东西掌握的都不是很好,如果你有自己的看法,请告知我,一起学习,一起进步:)
string Input = "Yours Input Msg";
if (Input == "")
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr ""
IL_000d: call bool [mscorlib]System.String::op_Equality(string,string)
2.使用String.Empty
string Input = "Yours Input Msg";
if (Input == String.Empty)
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldsfld string [mscorlib]System.String::Empty
IL_000d: call bool [mscorlib]System.String::op_Equality(string,string)
3.使用string.Length
string Input = "Yours Input Msg";
if (Input.Length == 0)
;
IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance int32 [mscorlib]System.String::get_Length()
在看过了三种方法之后,我们从底层开始进行比较,这里先做个假设,我们假设所有的单个IL语句执行时间相等,单位为1。(其实还是有差异的,但并不影响我们作比较。)
我们先反汇编mscorlib.dll得到System.String::op_Equality(strin,string):
.method public hidebysig specialname static
bool op_Equality(string a,
string b) cil managed
{
// 代码大小 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call bool System.String::Equals(string,
string)
IL_0007: ret
} // end of method String::op_Equality
发现他还要调用这个函数System.String::Equals(strin,string):
.method public hidebysig virtual instance bool
Equals(object obj) cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency,
valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 01 00 00 00 00 00 )
// 代码大小 23 (0x17)
.maxstack 2
.locals init (string V_0)
IL_0000: ldarg.1
IL_0001: isinst System.String
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_000f
IL_000a: ldarg.0
IL_000b: brfalse.s IL_000f
IL_000d: ldc.i4.0
IL_000e: ret
IL_000f: ldarg.0
IL_0010: ldloc.0
IL_0011: call bool System.String::EqualsHelper(string,
string)
IL_0016: ret
} // end of method String::Equals
然后还要调用System.String::EqualsHelper([b]string[/b],string):
.method private hidebysig static bool EqualsHelper(string strA,
string strB) cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency,
valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 01 00 00 00 00 00 )
// 代码大小 187 (0xbb)
.maxstack 3
.locals init (int32 V_0,
char* V_1,
char* V_2,
char* V_3,
char* V_4,
bool V_5,
string pinned V_6,
string pinned V_7)
IL_0000: ldarg.0
IL_0001: callvirt instance int32 System.String::get_Length()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.1
IL_0009: callvirt instance int32 System.String::get_Length()
IL_000e: beq.s IL_0012
IL_0010: ldc.i4.0
IL_0011: ret
IL_0012: ldarg.0
IL_0013: stloc.s V_6
IL_0015: ldloc.s V_6
IL_0017: conv.i
IL_0018: dup
IL_0019: brfalse.s IL_0021
IL_001b: call int32 System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0020: add
IL_0021: stloc.1
IL_0022: ldarg.1
IL_0023: stloc.s V_7
IL_0025: ldloc.s V_7
IL_0027: conv.i
IL_0028: dup
IL_0029: brfalse.s IL_0031
IL_002b: call int32 System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0030: add
IL_0031: stloc.2
IL_0032: ldloc.1
IL_0033: stloc.3
IL_0034: ldloc.2
IL_0035: stloc.s V_4
IL_0037: br.s IL_008b
IL_0039: ldloc.3
IL_003a: ldind.i4
IL_003b: ldloc.s V_4
IL_003d: ldind.i4
IL_003e: bne.un.s IL_00a9
IL_0040: ldloc.3
IL_0041: ldc.i4.4
IL_0042: conv.i
IL_0043: add
IL_0044: ldind.i4
IL_0045: ldloc.s V_4
IL_0047: ldc.i4.4
IL_0048: conv.i
IL_0049: add
IL_004a: ldind.i4
IL_004b: bne.un.s IL_00a9
IL_004d: ldloc.3
IL_004e: ldc.i4.8
IL_004f: conv.i
IL_0050: add
IL_0051: ldind.i4
IL_0052: ldloc.s V_4
IL_0054: ldc.i4.8
IL_0055: conv.i
IL_0056: add
IL_0057: ldind.i4
IL_0058: bne.un.s IL_00a9
IL_005a: ldloc.3
IL_005b: ldc.i4.s 12
IL_005d: conv.i
IL_005e: add
IL_005f: ldind.i4
IL_0060: ldloc.s V_4
IL_0062: ldc.i4.s 12
IL_0064: conv.i
IL_0065: add
IL_0066: ldind.i4
IL_0067: bne.un.s IL_00a9
IL_0069: ldloc.3
IL_006a: ldc.i4.s 16
IL_006c: conv.i
IL_006d: add
IL_006e: ldind.i4
IL_006f: ldloc.s V_4
IL_0071: ldc.i4.s 16
IL_0073: conv.i
IL_0074: add
IL_0075: ldind.i4
IL_0076: bne.un.s IL_00a9
IL_0078: ldloc.3
IL_0079: ldc.i4.s 20
IL_007b: conv.i
IL_007c: add
IL_007d: stloc.3
IL_007e: ldloc.s V_4
IL_0080: ldc.i4.s 20
IL_0082: conv.i
IL_0083: add
IL_0084: stloc.s V_4
IL_0086: ldloc.0
IL_0087: ldc.i4.s 10
IL_0089: sub
IL_008a: stloc.0
IL_008b: ldloc.0
IL_008c: ldc.i4.s 10
IL_008e: bge.s IL_0039
IL_0090: br.s IL_00a9
IL_0092: ldloc.3
IL_0093: ldind.i4
IL_0094: ldloc.s V_4
IL_0096: ldind.i4
IL_0097: bne.un.s IL_00ad
IL_0099: ldloc.3
IL_009a: ldc.i4.4
IL_009b: conv.i
IL_009c: add
IL_009d: stloc.3
IL_009e: ldloc.s V_4
IL_00a0: ldc.i4.4
IL_00a1: conv.i
IL_00a2: add
IL_00a3: stloc.s V_4
IL_00a5: ldloc.0
IL_00a6: ldc.i4.2
IL_00a7: sub
IL_00a8: stloc.0
IL_00a9: ldloc.0
IL_00aa: ldc.i4.0
IL_00ab: bgt.s IL_0092
IL_00ad: ldloc.0
IL_00ae: ldc.i4.0
IL_00af: cgt
IL_00b1: ldc.i4.0
IL_00b2: ceq
IL_00b4: stloc.s V_5
IL_00b6: leave.s IL_00b8
IL_00b8: ldloc.s V_5
IL_00ba: ret
} // end of method String::EqualsHelper
粗略估算了下,System.String::op_Equality(strin,string)执行时间大概是160。
这样方法1的大概运行时间是165,空间大概是220字节。方法2比只多了一次调用System.String::Empty(程序中的静态变量)
.field public static initonly string Empty
因此运行运行时间基本同方法1一致,空间上节省了2字节(原因是方法1需要先建立一个string类型("")后,再进行判断),可以忽略不计。很多文章谈到C#判断空字符串不同方法性能的时候往往以此为据,而看过上面的IL之后,我却不这么认为,真正的性能差异体现在了System.String::op_Equality(string,string)和System.String::get_Length()这两个函数之上。
下面我们看一下System.String::get_Length():
.method public hidebysig specialname instance int32
get_Length() cil managed internalcall
{
} // end of method String::get_Length
这个函数的函数体居然是空的?为什么?那难道这个不起作用吗?我认为是cil managed internalcall这个起了作用,取得字符串(内存中一块连续的区域)长度是非常快的,可以由CPU直接完成(这个是我的猜测,目前关于internalcall我们仅仅知道internalcall在RuntimeType类里面则是很容易就能够找到,速度很快,性能很高,这个可能涉及到程序的编译原理,不懂~~~)
反正这个函数很快很快就是了,那么方法3的运行时间大概只有6,空间大概是20多。
这样,我们得到了一个令人吃惊的结论,方法3在时间上只有前两种方法的约1/28,空间约是1/9。
为什么这样,我也不明白,我希望高手来指出我叙述或者论证不当的地方。
那么我们是否可以就直接使用方法3了呢?
答案是否定的。在C#使用属性时一定要注意异常捕捉的问题。
String的Length属性返回此实例中Char对象的个数,在C#中字符串可以看成是由多个Char组成的字符数组,这样如果String为null的话问题就来了,当String置为null时,相当于一个没有实例化的字符串数组,用Length取一个没有实例化数组的长度,那么产生异常就在所难免了。
因此应该这么做:
string Input = "Yours Input Msg";
if (Input!=null && Input.Length==0)
;
看一下IL:
.locals init ([0] string Input,[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Yours Input Msg"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0018
IL_000a: ldloc.0
IL_000b: callvirt instance int32 [mscorlib]System.String::get_Length()
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: ldc.i4.0
IL_0014: ceq
IL_0016: br.s IL_0019
运行时间大概是在5-13,空间越是30字节。这样,比起Input == ""这个方法,效率大约提高
13-30多倍(因为有短路运算),空间却只要1/7。
因此这些方法中判断字符串是否为空的最佳方法是:
desStr!=null && desStr.Length==0
本人初涉C#,很多东西掌握的都不是很好,如果你有自己的看法,请告知我,一起学习,一起进步:)
相关文章推荐
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- (转)判断一个字符串是否全是数字的多种方法及其性能比较(C#实现
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)--来源CSDN
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?
- 判断一个字符串是否全是数字的多种方法及其性能比较
- Java 判断字符串是否为空的三种方法性能比较
- C#之中的字符串替换方法以及判断是否存在特定子字符串
- C# 中如何判断某个字符串是否为空的方法
- Java判断字符串是否为空的三种方法
- C#判断一个字符串是否是数字或者含有某个数字的方法
- js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式
- java中判断字符串是否为数字的三种方法
- C#中判断字符串是否中文的方法
- Java判断字符串是否为空的三种方法
- 关于-c#字符串三种逆转方法及性能比较的另外看法