我想知道,在C#中构造新对象的首选方法是什么?
参加一个人类课程:
public class Person
{
private string name;
private int age;
//Omitted..
}
我应该创建它来使用:
New Person("name", 24);
或
New Person() { Name = "name", Age = 24 };
这只是一个品味的问题还是有充分的理由使用一个而不是另一个?
我可以想象一个人应该只使用构造函数中的必填字段和可选字段而不是构造函数参数,而是使用属性。
我是对的吗?
答案 0 :(得分:39)
首选方式取决于您的设计。
构造函数属性适用于对象为正确构造而需要的项目。也就是说,对象在初始化时应具有的任何属性都需要在构造函数中(除非您正在创建工厂或构建器模式,否则在调用构造函数之后通常不需要部分初始化对象)构造函数除了工厂/构建器之外都是隐藏的。
属性初始化器最适合在特定用例所需的构造函数之后进行其他配置,但对象不需要初始化。
例如,您可以拥有一个代表一个人的对象。一个人需要初始化名称和年龄,但他们所居住的地址是可选配置。因此,名称和年龄是构造函数参数,地址是读/写属性。
Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" };
答案 1 :(得分:12)
这实际上取决于场景。属性方法有很多方便,因为您不必在构造函数中复制赋值。此外,大多数数据绑定方案都喜欢能够创建新对象,他们通常使用无参数构造函数,因此这是一个很大的优势。
但是,对于不可变类型,构造函数方法是唯一明智的选择。有趣的是(也许)C#4.0中的命名/可选参数允许类似于不可变类型的对象初始化器 - see here。
构造函数方法对于Inversion of Control框架也非常流行,因为它明确地宣传了该类所需的功能。
您可能需要混合和匹配,但通常比构造函数样式更具属性。
答案 2 :(得分:7)
我总是在你应该将值传递给构造函数的基础上工作,这对于该对象必须存在于有效状态。
在你的例子中,你可以说没有年龄的新人不能存在,所以应该传递给构造函数。
如果您的工作基于对象应该为真实工作实体建模,那么确定使任何对象有效所需的最小值 - 无论您将它们设置为默认值还是通过构造函数传递值。
答案 3 :(得分:5)
在构造函数中设置值会使这些属性成为必需属性,因此这意味着您无法在不设置这些属性的情况下创建新实例。 在某些情况下,这是可取的,在其他情况下,这是不可预见的。
答案 4 :(得分:4)
一些想法:
您需要公共属性才能使用对象初始化器。因此,如果您不想公开某些内容,则必须通过构造函数参数对它们进行初始化。
如果检查IL,您会发现Object Initializer不是“原子”。如果您编写这样的代码(不是我推荐的,只是一个例子):
using (p = New Person() {Name = GetName(), Age = GetAge()})
{
//blah, blah
}
如果GetAge()
中存在异常,您将在损坏的状态下创建Person
的实例。更糟糕的是,您永远不能进入使用范围,并且该实例不会像您想象的那样处理。
答案 5 :(得分:2)
第二种方法是手动设置属性的语法糖:
Person p = new Person();
p.Name = "name";
p.Age = 24;
您也不依赖于可能无法初始化您想要设置的所有属性的构造函数。
如果你的类有一个需要这两个参数的构造函数,你就不会明确地调用那个构造函数。
答案 6 :(得分:2)
在我看来,你应该首先决定什么使一个人成为一个人。正确实例化人物对象的人物属性是什么。一个人的最低要求是什么。
应始终有一个具有最低要求的构造函数。
我只对不需要实例化任何属性的类型使用对象初始值设定项。因此是默认构造函数。
我知道对象初始化器非常方便。其他机制也可能需要对象中的空构造函数。
但我不认为你可以创建一个没有名字的人很有道理。
答案 7 :(得分:0)
我对这个问题的主要考虑因素是:1)当实例化对象时,实例化实体将拥有多少数据; 2)该类需要封装的程度如何?如果一旦设置,属性不应该改变(至少,由于任何外部实体),那么我将使用构造函数,因为构造函数可以设置任何只读属性以及任何读/写属性。
还要记住,就像任何其他方法一样,您的构造函数可能会被重载,因此您可以设置任意数量的方法来初始化这些属性。
通常,我使用构造函数,但有时我会手动设置属性。使用正确的工具来解决正确的问题。
答案 8 :(得分:0)
要手动设置属性,必须将它们声明为public,并且您可能希望类成员是私有的。在这种情况下,构造函数是可行的方法,或编写方法来获取/设置它们或使用访问器。
答案 9 :(得分:0)
我倾向于选择一个带有属性初始化器的非常简单的构造函数。我发现它会导致更明确的代码。我传递给构造函数的唯一数据是在创建类时我不希望我的类用户改变的信息。
答案 10 :(得分:0)
当您通过层/层传递对象时,会出现真正的问题。例如,您创建一个人物对象并通过Web服务。 somepoint上的webservice尝试反序列化并尝试实例化,如果构造函数需要参数,则可能会出错!因为webservices首先创建一个对象,然后分配值。
所以我更喜欢无参数的构造函数,如果它是需要通过层的数据模型(POCO类型)。
由于其他原因,contructor参数是最好的方法(对于必填字段)。特别是在将类作为外部对象或组件的接口时提供。