在C#中构造对象的首选方法是什么?构造函数参数还是属性?

在C#中构造对象的首选方法是什么?构造函数参数还是属性?,c#,oop,properties,constructor,C#,Oop,Properties,Constructor,我想知道,在C#中构造新对象的首选方法是什么 以个人为例: public class Person { private string name; private int age; //Omitted.. } 我是否应该创建它以使用: New Person("name", 24); 或 这仅仅是一个品味的问题,还是有一个很好的理由使用一个而不是另一个 我可以想象,应该只使用构造函数中的必填字段,而不使用可选字段作为构造函数参数,而是使用属性 我说的对吗?第二种方法是

我想知道,在C#中构造新对象的首选方法是什么

以个人为例:

public class Person 
{
    private string name;
    private int age;

    //Omitted..
}
我是否应该创建它以使用:

New Person("name", 24);

这仅仅是一个品味的问题,还是有一个很好的理由使用一个而不是另一个

我可以想象,应该只使用构造函数中的必填字段,而不使用可选字段作为构造函数参数,而是使用属性


我说的对吗?

第二种方法是手动设置属性的语法糖:

Person p = new Person();
p.Name = "name";
p.Age = 24;
您也不依赖于构造函数,因为构造函数可能不会初始化所有要设置的属性


如果您的类有一个需要这两个参数的构造函数,那么您就没有时间显式调用该构造函数。

这实际上取决于场景。属性方法非常方便,因为您不必在构造函数中重复赋值。此外,大多数数据绑定场景都希望能够创建新对象,对于这些对象,它们通常使用无参数构造函数,因此这是一个很大的优势

然而,对于不可变类型,构造函数方法是唯一明智的选择。有趣的是(也许)C#4.0中的命名/可选参数允许类似于不可变类型的对象初始化器-

构造函数方法对于控制框架的反转也是非常流行的,因为它清楚地宣传了类需要什么才能运行


您可能需要混合和匹配,但通常属性样式多于构造函数样式。

在构造函数中设置值会使这些属性成为必需的,因此这意味着您无法在没有设置这些属性的情况下创建新实例。
在某些情况下,这是最好的,在其他情况下,这是不可预处理的。

我在这个问题上的主要考虑是:1)实例化对象时,实例化实体将有多少数据;2)类需要如何封装?如果一旦设置,属性就不能更改(至少由于任何外部实体),那么我将使用构造函数,因为构造函数可以设置任何只读属性以及任何读/写属性

还请记住,与任何其他方法一样,构造函数可以重载,因此可以设置任意数量的方法来初始化这些属性


通常,我使用构造函数,但有时我会手动设置属性。使用正确的工具解决正确的问题。

我的工作始终基于这样一个基础:您应该将值传递给构造函数,这是该对象以有效状态存在所必需的

在你的例子中,你可以说没有年龄的人是不可能存在的,所以应该把年龄传给建设者


如果你的工作是基于一个对象应该为一个真实的工作实体建模,那么这就决定了使任何对象有效所需的最小值——不管你是将其设置为默认值还是通过构造函数传入值。

在我看来,你应该首先决定是什么使一个人成为一个人。要正确实例化person对象,person的属性是什么。对一个人的最低要求是什么

应该始终有一个具有最低要求的构造函数

我只对不需要实例化任何属性的类型使用对象初始值设定项。因此是默认构造函数

我知道对象初始值设定项非常方便。其他机制也可能需要对象中的空构造函数

但是我不认为你可以创造一个没有名字的人有多大意义。

一些想法:

  • 您需要公共属性才能使用对象初始值设定项。所以,如果您不想公开某些内容,则必须通过构造函数参数对其进行初始化

  • 如果您检查IL,您将发现对象初始值设定项不是“原子的”。如果您编写这样的代码(不是我推荐的,只是一个示例):

    如果
    GetAge()
    中存在异常,您将创建处于损坏状态的
    Person
    的实例。更糟糕的是,您永远无法进入使用范围,并且该实例不会像您想象的那样被处理


  • 首选方式取决于您的设计

    构造函数属性用于对象正确构造所需的项。也就是说,为了初始化对象,该对象应该具有的任何属性都需要在构造函数中(在调用构造函数之后,通常不需要部分初始化的对象,除非您正在创建工厂或构建器模式,并且构造函数对工厂/构建器之外的所有对象都隐藏)

    属性初始化器最适合在特定用例所需的构造函数之后进行额外配置,但不需要对对象进行初始化

    例如,可以有一个表示人的对象。一个人需要姓名和年龄进行初始化,但他们居住的地址是可选配置。因此,name和age是构造函数参数,address是读/写属性

    Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" };
    

    对于手动设置属性,它们必须声明为公共的,并且您可能希望类成员是私有的。在这种情况下,构造函数是一种方法,或者编写方法来获取/设置它们,或者使用访问器。

    我倾向于使用带有属性初始化器的非常简单的构造函数。我发现这会导致更明确的代码。我将传递给构造函数的唯一数据是我不希望我的类的用户在创建该类后更改的信息。

    当您通过层/层传递对象时,真正的问题出现了。例如,您创建一个person对象并通过一个webservice。Web服务在某个点尝试反序列化并尝试实例化
    using (p = New Person() {Name = GetName(), Age = GetAge()})
    {
      //blah, blah
    }
    
    Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" };