创建对象的最佳方法

28

这似乎是一个非常愚蠢和基础的问题,但我尝试通过谷歌搜索,却找不到一个令人满意的答案,

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(){}
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    //Other properties, methods, events...
}

我的问题是,如果我有这样的一个类,创建对象的最佳方式是什么?

Person p=new Person("abc",15)

或者

Person p=new Person();
p.Name="abc";
p.Age=15;

这两种方法有什么区别,哪一种是创建对象的最佳方式?


11
为了增加第三种选项:Person p=new Person { Name="abc", Age=15 }; - 或者第四种:Person p = new Person(name: "abc", age: 15);。正如X.L.Ant所说:没有一种自动“更好”。 - Marc Gravell
8个回答

38

确定你是否需要一个不可变的对象。

如果您在类中放置public属性,则每个实例的状态都可以在代码的任何时候更改。因此,您的类可能是这样的:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(){}
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    //Other properties, methods, events...
}
在这种情况下,拥有一个Person(string name, int age)构造函数并不是那么有用。
第二种选择是实现一个不可变类型。例如:
public class Person
{
    public string Name { get; private set; }
    public int Age { get; private set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    //Other properties, methods, events...
}

现在你有一个构造函数,它在创建实例时为状态设置了一次。请注意,现在属性的setter是私有的,所以在实例化对象后无法更改状态。

最佳实践是尽可能将类定义为不可变的。要了解不可变类的优点,建议阅读这篇文章


1
你的不可变类应该有公共的getter方法和私有的setter方法。 - Servy
自 C# 6 开始,你可以完全删除 setter 方法来创建只读属性。这实际上会确保在构造函数之外不会意外修改属性。 - Kyle

11

取决于您的要求,尽管最近我看到了至少定义了一个空构造函数的类的趋势。

通过构造函数传递参数的好处是,您在实例化后知道这些值是可靠的。缺点是,您需要在任何希望能够使用空构造函数创建对象的库中进行更多的工作。

我的个人偏好是选择空构造函数,并将任何属性作为声明的一部分设置。

Person p=new Person()
{
   Name = "Han Solo",
   Age = 39
};

这种方法可以避免“类缺乏无参构造函数”的问题,还可以降低维护成本(我可以在不改变构造函数的情况下设置更多东西)。


可以使用上述的构造函数,但在声明值后仍然对其进行操作吗?目前我在程序中到处都在使用这种类型的构造函数,但现在我需要添加额外的构造函数逻辑(使用其中一个参数)——这是一个重大疏忽。 - Sinjai

6

其实没有最好的方法。两种方式都差不多,除非您想在初始化期间使用传递给构造函数的参数进行一些额外处理或者在调用构造函数后确保一个一致的状态。如果是这种情况,请选择第一种方法。

但出于可读性/可维护性的原因,应避免创建具有过多参数的构造函数。

在这种情况下,两种方法都可以。


1
如果类在构造函数中不需要参数,那么测试类会更容易。 - GodsCrimeScene

6
在我看来,这只是决定参数是可选还是必须的问题。如果一个Person对象在没有Name和Age的情况下(从逻辑上)不存在,那么它们应该在构造函数中是必须的。如果它们是可选的(即它们的缺失不会威胁到对象的良好功能),则使用setters。
以下是Symfony文档中关于构造函数注入的引用:
"使用构造函数注入有几个优点: - 如果依赖是必需的,并且类在没有它的情况下无法工作,则通过构造函数注入确保在使用类时存在,因为不能构造没有它的类。 - 构造函数仅在创建对象时调用一次,因此您可以确定依赖项在对象的生命周期内不会更改。
这些优点意味着构造函数注入不适用于处理可选依赖项。它在与类层次结构组合使用时也更难使用:如果一个类使用构造函数注入,则扩展它并覆盖构造函数变得棘手。"
(Symfony是最受欢迎和受尊敬的php框架之一)

5

怎么样

var obj = new {ID = 1, Price = 2};

4
如果您认为代码量越少就越有效率,那么使用构造函数会更好。您也可以使用以下类似的代码:
Person p=new Person(){
Name='abc',
Age=15
}

1
根据您的需求,但创建最有效的方法是:
 Product obj = new Product
            {
                ID = 21,
                Price = 200,
                Category = "XY",
                Name = "SKR",
            };

0

或者您可以使用数据文件将许多人物对象放入列表或数组中。您需要使用System.IO进行此操作。并且您需要一个包含有关对象的所有信息的数据文件。

其方法可能如下所示:

static void ReadFile()
{
    using(StreamWriter writer = new StreamWriter(@"Data.csv"))
    {
        string line = null;
        line = reader.ReadLine();
        while(null!= (line = reader.ReadLine())
                {
                    string[] values = line.Split(',');
                    string name = values[0];
                    int age = int.Parse(values[1]);
                }
        Person person = new Person(name, age);
    }
}

如果没有重载可释放函数,您不能在自定义类中使用using()。 - habib

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