C# 变量初始化:直接还是在构造函数中?

C# 变量初始化:直接还是在构造函数中?,c#,initialization,C#,Initialization,可能重复: 大多数时候,我看到了初始化变量的方法,就像这样 public class Test { private int myIntToInitalize; public Test() { myIntToInitalize = 10; } } 在我看来,这是初始化变量最常用的方法。书籍、博客以及.NET内部实现中的大部分代码都与我的示例相同 最近,我看到人们直接进行初始化,因此没有在构造函数中设置值 public class Test {

可能重复:

大多数时候,我看到了初始化变量的方法,就像这样

public class Test
{
    private int myIntToInitalize;

    public Test()
    {
        myIntToInitalize = 10;
    }
}
在我看来,这是初始化变量最常用的方法。书籍、博客以及.NET内部实现中的大部分代码都与我的示例相同

最近,我看到人们直接进行初始化,因此没有在构造函数中设置值

public class Test
{
    private int myIntToInitalize = 10;
}
从这个角度来看,初始化和声明变量与在构造函数中初始化变量没有区别

public class Test
{
    private int myIntToInitalize = 10;
}

除了最佳实践和代码行长度之外,直接初始化变量的好处在哪里?是否存在细微的差异?

我不知道有任何细微的差异。我通常喜欢将所有初始化都放在构造函数中,因为我认为这会使代码更具可读性。但这更多的是一种风格选择和个人偏好。我还没听说过有什么技术上的理由来证明这一点。我怀疑这会对性能产生任何影响


静态常数和最终常数是不同的。我在线初始化这些变量。

构造实例时,在声明时初始化的任何变量都将在构造函数运行之前初始化。如果您没有访问这些变量或在构造函数本身中使用它们的值,那么这两种方法之间就没有功能上的差异。

在某些情况下,有一个潜在的显著差异

实例初始值设定项在执行基类构造函数之前执行。因此,如果基类构造函数调用派生类中重写的任何虚拟方法,该方法将看到差异。然而,通常这不应该是一个明显的区别,因为在构造函数中调用虚拟方法几乎总是一个坏主意

为了清楚起见,如果您在声明点初始化变量,那么很明显该值不依赖于任何构造函数参数。另一方面,在我看来,将所有初始化放在一起也有助于可读性。我会尽可能确保,如果你有多个构造函数,它们都会委托给一个“主”构造函数来完成所有“真正”的初始化,这意味着你只能将这些赋值放在一个地方

演示差异的示例代码:

using System;

class Base
{
    public Base()
    {
        Console.WriteLine(ToString());
    }
}

class Derived : Base
{
    private int x = 5;
    private int y;

    public Derived()
    {
        y = 5;
    }

    public override string ToString()
    {
        return string.Format("x={0}, y={1}", x, y);
    }
}

class Test
{
    static void Main()
    {
        // Prints x=5, y=0
        new Derived();
    }
}

举个简单的例子,这只是风格的问题

当涉及到继承时,会有细微的差别。例如字段初始值设定项,执行顺序为派生类字段初始值设定项、基类字段初始值设定项、基类构造函数、派生类构造函数

以这个样本为例:

public class Program
{
    public static void Main(string[] args)
    {
        new Derived();
    }
 }

 public class Base 
 {
     private int x = BaseInitializer();

     public Base()
     {
          Console.WriteLine("Base ctor");
     }

     private static int BaseInitializer()
     {
         Console.WriteLine("BaseInitializer");
         return 0;
     }
 }

 public class Derived : Base
 {
     private int x = DerivedInitializer();

     public Derived() : base()
     {
         Console.WriteLine("Derived ctor");
     }

     private static int DerivedInitializer()
     {
         Console.WriteLine("DerivedInitializer");
         return 0;
     }
 }
它打印:

  • 衍生初始值设定项
  • 碱基初始值设定项
  • 基极导体
  • 导出的向量
在类Test1上,每个对象实例都将myIntToInitalize设置为10,
但是当你调用需要1个参数的构造函数时,类Test2上就没有了。

假设我们在发布和优化版本下编译以下代码

namespace ConsoleApplication4
{

    public class Test1
    {
        private int myIntToInitalize;

        public Test1()
        {
            myIntToInitalize = 10;
        }
    }

    public class Test2
    {
        private int myIntToInitalize = 10;
    }


    static class Program
    {

        private static void Main()
        {
        }


    }

}
Test1类的IL指令

.class public auto ansi beforefieldinit Test1
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ldarg.0 
        L_0007: ldc.i4.s 10
        L_0009: stfld int32 ConsoleApplication4.Test1::myIntToInitalize
        L_000e: ret 
    }


    .field private int32 myIntToInitalize

}
Test2类的IL指令

.class public auto ansi beforefieldinit Test2
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: ldc.i4.s 10
        L_0003: stfld int32 ConsoleApplication4.Test2::myIntToInitalize
        L_0008: ldarg.0 
        L_0009: call instance void [mscorlib]System.Object::.ctor()
        L_000e: ret 
    }


    .field private int32 myIntToInitalize

}
很明显,这两个类都有相同数量的IL指令,唯一的区别是

在类Test1中调用::ctor()之前初始化变量; 和 在类Test2中调用::ctor()后初始化变量


注意:从性能角度看,这两个类的性能都是相同的,因为它们有相同数量和类型的IL指令,只是IL指令的执行顺序不同

可能重复,我认为使用构造函数是完全多余的。为什么要把事情复杂化,编写更多冗余代码?我通常只在无法直接进行初始化时才在构造函数中进行初始化,例如当必须将一些参数传递给变量初始化所依赖的构造函数时。否则:private int myIntToInitalize=10;不要把事情搞得太复杂,让它们尽可能简单。代码越少越好!!!它们甚至在基类构造函数运行之前就已经运行了。这在处理虚拟方法时变得更加重要。从构造函数调用虚拟方法不是一个好的做法,但是如果您从基构造函数调用aVirtualMethod,并且派生的类会覆盖它,那么您会发现在执行aVirtualMethod之前会“执行”任何变量初始值设定项,但派生的构造函数还不会执行。其他信息: