使用类变量的默认值而不是在c#中初始化它是否会影响性能?
我最近遇到一个人,他提到如果我们要用默认值初始化类变量,就不应该初始化它。 我觉得这听起来很不对。这有没有实际的性能提升? 在下面的示例中,他最初不希望将标志设置为false(尽管在场景中假定为false) C#不允许使用未定义的变量。CLR仍然初始化为默认值。如果可能的话不设置变量,编译器将在稍后检查断言时设置该变量使用类变量的默认值而不是在c#中初始化它是否会影响性能?,c#,C#,我最近遇到一个人,他提到如果我们要用默认值初始化类变量,就不应该初始化它。 我觉得这听起来很不对。这有没有实际的性能提升? 在下面的示例中,他最初不希望将标志设置为false(尽管在场景中假定为false) C#不允许使用未定义的变量。CLR仍然初始化为默认值。如果可能的话不设置变量,编译器将在稍后检查断言时设置该变量 OTOH,fields没有这样的检查。当将默认值设置为默认值时,调试器会逐步将所有这些字段设置为这些默认值,这可能会造成麻烦。不设置它们可能会有QoL改善wrt调试体验如果您已确
OTOH,fields没有这样的检查。当将默认值设置为默认值时,调试器会逐步将所有这些字段设置为这些默认值,这可能会造成麻烦。不设置它们可能会有QoL改善wrt调试体验如果您已确定您引用的是一个bool字段,该字段是一个隐藏的值对象,不能为空。默认设置为“false” bool变量的默认值为false 我最近遇到一个人,他提到我们不应该初始化类变量…如果我们要用默认值初始化它 我同意,但是 这有没有实际的性能提升 不,完全一样。区别只是风格的问题 让我们仔细看看。让我们让您的类的变体不设置您的标志,将其初始化为默认值,否则将其初始化,并在构造函数中执行这两项操作:
public class NoInit
{
private bool _flag;
}
public class DefaultInit
{
private bool _flag = false;
}
public class NonDefaultInit
{
private bool _flag = true;
}
public class TestDefaultCtor
{
private bool _flag;
public TestDefaultCtor()
{
_flag = false;
}
}
public class TestNonDefaultCtor
{
private bool _flag;
public TestNonDefaultCtor()
{
_flag = true;
}
}
现在让我们编译发布版本:
.class public auto ansi beforefieldinit NoInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib] System.Object::.ctor()
IL_0006: ret
}
}
.class public auto ansi beforefieldinit DefaultInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib] System.Object::.ctor()
IL_0006: ret
}
}
.class public auto ansi beforefieldinit NonDefaultInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: stfld bool NonDefaultInit::_flag
IL_0007: ldarg.0
IL_0008: call instance void [mscorlib] System.Object::.ctor()
IL_000d: ret
}
}
.class public auto ansi beforefieldinit TestDefaultCtor
extends [mscorlib]System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldc.i4.0
IL_0008: stfld bool TestDefaultCtor::_flag
IL_000d: ret
}
}
.class public auto ansi beforefieldinit TestNonDefaultCtor
extends [mscorlib]System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: stfld bool TestNonDefaultCtor::_flag
IL_000d: ret
}
}
正如您所看到的,虽然将标志设置为true会产生效果(当然,它必须发生在某个地方),但在构造函数中将其设置为false确实会导致显式编译设置为false(尽管,这并不一定意味着一旦jitted就有任何区别),在DefaultInit
和NoInit
之间,它的编译目的没有区别。如果我们要将它反编译回C#,我们必须自己调用,明确地将它设置为false,而不是像最初编写它时那样
因此,就结果而言,两者完全相同
这并不是说差别完全不重要。(我认为我更希望我正在从事的项目始终使用我不喜欢的方法,而不是前后不一致;前后不一致更糟糕)
但是,很多初始化可能会有点忙,并且不会向有足够经验的编码器添加任何信息*,以了解什么类型的默认值,并在我们出于某种原因初始化特定值时使其更清晰
如果我们要(或有时要)在构造函数中设置值,那么它也可能显得特别冗余。(注意,初始化为构造函数中的默认设置与编译构造函数中的设置没有什么不同,但如果我们初始化为非默认设置,则情况并非如此。在jitting时,通常会对非默认设置进行优化,但并非总是如此,尤其是当初始化有副作用时)
在调试会话期间,它还可以导致较低的信噪比,从而发生大量无趣的初始化
所以,我认为有编码约定是合理的,我同意你提到的那个人的看法,我希望这些约定是什么,但它们是约定,不是影响性能的东西
*相比之下,使用
private
或internal
作为默认值,至少可以添加一个人是否分别位于类或命名空间上下文中的信息(这使得这些内容分别成为默认值),因此读者可以少想一件事。所以我更喜欢显式的。运行代码并找出答案。这个链接只说new int()
与初始化到0
相同,但与不初始化变量无关。@crashmstr:我想OP使用该页作为默认值的引用,而不是断言的来源。也就是说,“我的朋友说我们不应该将变量初始化为列出的默认值。”你具体读到/听到了什么导致你提出这个问题?在问题C#中添加了更多细节,不允许使用未定义的变量。
这不是真的。某些变量(即局部变量)需要初始化,但不是全部。下面是一个很好的答案,解释了为什么不允许未定义局部变量,而类变量是:它主要与检测某些内容是否实际未分配的复杂性有关。
.class public auto ansi beforefieldinit NoInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib] System.Object::.ctor()
IL_0006: ret
}
}
.class public auto ansi beforefieldinit DefaultInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib] System.Object::.ctor()
IL_0006: ret
}
}
.class public auto ansi beforefieldinit NonDefaultInit
extends [mscorlib] System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: stfld bool NonDefaultInit::_flag
IL_0007: ldarg.0
IL_0008: call instance void [mscorlib] System.Object::.ctor()
IL_000d: ret
}
}
.class public auto ansi beforefieldinit TestDefaultCtor
extends [mscorlib]System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldc.i4.0
IL_0008: stfld bool TestDefaultCtor::_flag
IL_000d: ret
}
}
.class public auto ansi beforefieldinit TestNonDefaultCtor
extends [mscorlib]System.Object
{
.field private bool _flag
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: stfld bool TestNonDefaultCtor::_flag
IL_000d: ret
}
}