class 声明 v/s 构造函数中初始化对象的区别
Difference on initializing object inside class declaration v/s constructor
我正在为我的对象进行对象初始化和构造函数初始化,但无法得到对我的问题的准确答复。
这里的Case1和Case2有什么区别;
案例一:
namespace ConsoleApplication2
{
class MyBuilder
{
private MySynchronizer m_synchronizer = new MySynchronizer();
public MyBuilder()
{
}
public void ProcessRecord(int recordNumber)
{
m_synchronizer.Process(recordNumber);
}
}
}
案例二:
namespace ConsoleApplication2
{
class MyBuilder
{
private MySynchronizer m_synchronizer;
public MyBuilder()
{
m_synchronizer = new MySynchronizer();
}
public void ProcessRecord(int recordNumber)
{
m_synchronizer.Process(recordNumber);
}
}
}
这是展示我如何调用我的生成器的示例代码class;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to stop");
MyBuilder builder = new MyBuilder();
builder.ProcessRecord(2);
}
}
[抱歉,如果我不能正确地重新表述问题,在这种情况下任何人都可以向其他 SO 文章提供 link]
这里的区别是真的微妙的,只能很容易在 IL 中理解:
class MyBuilder1
{
private MySynchronizer m_synchronizer = new MySynchronizer();
public MyBuilder1()
{
}
}
给我们构造函数:
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: newobj instance void MySynchronizer::.ctor()
IL_0006: stfld class MySynchronizer MyBuilder1::m_synchronizer
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method MyBuilder1::.ctor
哪里-像这样:
class MyBuilder2
{
private MySynchronizer m_synchronizer;
public MyBuilder2()
{
m_synchronizer = new MySynchronizer();
}
}
给我们:
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2063
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: newobj instance void MySynchronizer::.ctor()
IL_000c: stfld class MySynchronizer MyBuilder2::m_synchronizer
IL_0011: ret
} // end of method MyBuilder2::.ctor
区别只是顺序之一:
- 字段初始值设定项 (
MyBuilder1
) 发生在 之前 基类型构造函数调用(object
是这里的基础;call instance void [mscorlib]System.Object::.ctor()
是基础构造函数调用)
- 构造函数发生在之后基类型构造函数调用
在大多数情况下,这无关紧要。除非你的基础构造函数调用派生类型重写的虚方法:否则字段在重写方法中是否具有值在两者之间是不同的。
我几乎总是选择第二个选项(在构造函数中初始化)。在我看来,它使您的代码更具可读性,并且控制逻辑位于构造函数内部,这为将来添加逻辑提供了更大的灵活性。
不过,这只是我个人的意见。
正如@Marc 已经提到的,区别在于基本构造函数的顺序。
我添加了基础构造函数
class Base
{
public Base()
{
Console.WriteLine("Inside Base constructor");
}
}
并将我的 class "MyBuilder" 修改为从中派生为;
class MyBuilder : Base
{
}
现在,案例 1 的输出如下所示:
而案例 2:
因此,
- 如果您有多个构造函数,那么 case1 方法可能更好,因为它不太容易出错,因为有人可以轻松添加另一个构造函数而忘记链接它。
- 如果您只有一个构造函数并且没有任何依赖于基本构造函数顺序的逻辑流,那么 case2 似乎更好,因为这将使代码更清晰。 [无意冒犯,个人喜好]
我正在为我的对象进行对象初始化和构造函数初始化,但无法得到对我的问题的准确答复。 这里的Case1和Case2有什么区别;
案例一:
namespace ConsoleApplication2
{
class MyBuilder
{
private MySynchronizer m_synchronizer = new MySynchronizer();
public MyBuilder()
{
}
public void ProcessRecord(int recordNumber)
{
m_synchronizer.Process(recordNumber);
}
}
}
案例二:
namespace ConsoleApplication2
{
class MyBuilder
{
private MySynchronizer m_synchronizer;
public MyBuilder()
{
m_synchronizer = new MySynchronizer();
}
public void ProcessRecord(int recordNumber)
{
m_synchronizer.Process(recordNumber);
}
}
}
这是展示我如何调用我的生成器的示例代码class;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to stop");
MyBuilder builder = new MyBuilder();
builder.ProcessRecord(2);
}
}
[抱歉,如果我不能正确地重新表述问题,在这种情况下任何人都可以向其他 SO 文章提供 link]
这里的区别是真的微妙的,只能很容易在 IL 中理解:
class MyBuilder1
{
private MySynchronizer m_synchronizer = new MySynchronizer();
public MyBuilder1()
{
}
}
给我们构造函数:
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: newobj instance void MySynchronizer::.ctor()
IL_0006: stfld class MySynchronizer MyBuilder1::m_synchronizer
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method MyBuilder1::.ctor
哪里-像这样:
class MyBuilder2
{
private MySynchronizer m_synchronizer;
public MyBuilder2()
{
m_synchronizer = new MySynchronizer();
}
}
给我们:
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2063
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: newobj instance void MySynchronizer::.ctor()
IL_000c: stfld class MySynchronizer MyBuilder2::m_synchronizer
IL_0011: ret
} // end of method MyBuilder2::.ctor
区别只是顺序之一:
- 字段初始值设定项 (
MyBuilder1
) 发生在 之前 基类型构造函数调用(object
是这里的基础;call instance void [mscorlib]System.Object::.ctor()
是基础构造函数调用) - 构造函数发生在之后基类型构造函数调用
在大多数情况下,这无关紧要。除非你的基础构造函数调用派生类型重写的虚方法:否则字段在重写方法中是否具有值在两者之间是不同的。
我几乎总是选择第二个选项(在构造函数中初始化)。在我看来,它使您的代码更具可读性,并且控制逻辑位于构造函数内部,这为将来添加逻辑提供了更大的灵活性。
不过,这只是我个人的意见。
正如@Marc 已经提到的,区别在于基本构造函数的顺序。
我添加了基础构造函数
class Base
{
public Base()
{
Console.WriteLine("Inside Base constructor");
}
}
并将我的 class "MyBuilder" 修改为从中派生为;
class MyBuilder : Base
{
}
现在,案例 1 的输出如下所示:
而案例 2:
因此,
- 如果您有多个构造函数,那么 case1 方法可能更好,因为它不太容易出错,因为有人可以轻松添加另一个构造函数而忘记链接它。
- 如果您只有一个构造函数并且没有任何依赖于基本构造函数顺序的逻辑流,那么 case2 似乎更好,因为这将使代码更清晰。 [无意冒犯,个人喜好]