我应该使用对象初始化器还是构造函数?

10

我刚学习了对象初始化程序,想知道何时使用它们最佳实践。

这是我读到的内容:http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx 它明确指出它们用于创建匿名类型,但我想知道在所有其他情况下是否应尽量优先使用它们而不是普通构造函数。


https://dev59.com/W3RB5IYBdhLWcg3wCjgV - dugas
5
这可能有些主观。有一个不可变类型?需要封装状态的对象?声明可注入依赖关系的对象?最好使用构造函数。有一个简单(但可变)的DTO?可以使用初始化程序语法。使用适合您要完成任务的工具。 - Anthony Pegram
即使在一个简单的DTO中,我仍然会使用构造函数参数来传递类必需的数据。 - Reed Copsey
4个回答

28
我想说不需要在所有其他情况下都使用对象初始化器代替普通的构造函数。
构造函数具有许多优点。使用构造函数,编译器将强制要求为您的类型提供所有必需的数据。这意味着您可以防止创建无效状态实例,从而积极地预防许多错误。
另一方面,对象初始化器会带来许多缺点。您必须为需要初始化的任何数据提供公开可设置的属性。它们不是在构造时必需的,因此您的类型的用户可能会意外遗漏一些数据。
一般来说,对于类的正常运行所需的任何内容都应该在构造函数中要求。即使您有自定义构造函数,仍然可以使用对象初始化器,但只应用于在类上设置为可选的数据。在初始化中混合两者没问题,这意味着您可以执行以下操作:
var yourInst = new YourClass(req1, req2) { OptionalProperty = opt1 }

这可以帮助减少所需的构造函数重载数量(类似于使用可选参数,但没有可选参数版本控制的一些缺点)。


此外,如果您使用对象初始化程序的原因是为了可读性,请考虑在构造函数中使用命名参数 - https://learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments。 - ethane

10

我认为您对事情产生了混淆。

对象初始化程序调用类的默认(或指定的)构造函数!因此,您不能真正使用对象初始化程序替代普通构造函数。因此,在使用对象初始化程序时,您仍然在调用构造函数。

如果您想了解设计中的类的对象初始化程序,则答案仍然适用。确保提供有意义的必要构造函数即可。您无需执行任何特殊操作以启用/允许对象初始化程序。它们是C#编译器自版本3.0以来提供的语法糖,允许您类的用户在构造后立即初始化类的公共成员。


因此,使用对象初始化程序将调用默认构造函数。 - Zapnologica
是的,可以使用默认构造函数或与您的初始化器匹配的专用构造函数。 - Mike Dinescu

6
一个好的经验法则是:
  • 如果必须使类正常运作,那么它应该是构造函数参数。
  • 如果更改它会破坏类,那么它也应该是构造函数参数。
  • 如果它是可选的、有一个合理的默认值,或者只是安全地改变了类的行为,那么它应该是一个初始化器。
初始化器的主要优点是,在创建对象时您不必立即设置它们 - 您可以根据其他逻辑稍后设置它们。

1
我目前认为使用它们存在以下问题:
  1. 分配的属性必须是可变的。这似乎是不可取的,因为如果将数据传递给构造函数,在那里可以检查它,并在提供的数据不足或错误时使对象创建失败。如果可以使用属性分配数据,我突然需要弄清楚我的对象状态是什么,是否已经正确地创建了所有内容,或者我可能处于其他状态。
  2. 分配的属性必须是公共的。这意味着访问可能是私有的东西必须被公开,然后通过使用接口或类似的方式进行限制。
因此,我的工作理论是:不要使用对象初始化器,它们会鼓励愚蠢的事情。

我同意这个观点,但是如果你仅仅是使用一个构造器类来初始化一个不可变类的私有构造器,那么这是完全可以接受的。当然,对于仅在狭小范围内使用的东西也是可以的。 - Matthew Watson
创建对象失败的唯一方式是抛出异常。 - Bobson
1
正如Miky所说,你混淆了事情。对象初始化器应该只用于使代码更清晰。你仍然编写相同的基础代码,只是使用方式不同。请参见@dugas提供的链接中Reed的答案。 - Justin Pihony
@Bobson:他的意思是,如果你使用属性来初始化对象,必须能够在不设置该/这些属性的情况下创建它。 - Matthew Watson
这对我来说没有意义 - 如果更改可写属性会导致类构造失败,为什么要有它们?如果在构造后设置会发生什么? - Ani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接