如何使用构造函数初始化一个列表?

41

我有一个类型:

public  class Human
{
    public int Id { get; set; }
    public string Address { get; set; }
    public string Name { get; set; }
    public List<ContactNumber> ContactNumbers { get; set; }

    public Human(int id)
    {
        Id = id;
    }

    public Human(int id, string address, string name,
                 List<ContactNumber> contactNumbers) :
        this(id)
    {
        Address = address;
        Name = name;
        ContactNumbers = contactNumbers;
    }        
}
请指导我,在使用构造函数进行列表初始化时,是否是最佳实践之一? 如何使用构造函数初始化列表?
编辑:
请指导我,在使用构造函数进行列表初始化时,是否是最佳实践之一? 如何使用构造函数为列表赋值,使得如果没有传递值,则使用默认值?
谢谢。
5个回答

67

使用集合初始化器

从C# 3开始,您可以使用集合初始化器构造List并使用一个表达式填充它。以下示例构造了一个Human及其ContactNumbers:

var human = new Human(1, "Address", "Name") {
    ContactNumbers = new List<ContactNumber>() {
        new ContactNumber(1),
        new ContactNumber(2),
        new ContactNumber(3)
    }
}

定制Human构造函数

您可以更改Human类的构造函数,以提供一种填充ContactNumbers属性的方式:

public class Human
{
    public Human(int id, string address, string name, IEnumerable<ContactNumber> contactNumbers) : this(id, address, name)
    {
        ContactNumbers = new List<ContactNumber>(contactNumbers);
    }

    public Human(int id, string address, string name, params ContactNumber[] contactNumbers) : this(id, address, name)
    {
        ContactNumbers = new List<ContactNumber>(contactNumbers);
    }
}

// Using the first constructor:
List<ContactNumber> numbers = List<ContactNumber>() {
    new ContactNumber(1),
    new ContactNumber(2),
    new ContactNumber(3)
};

var human = new Human(1, "Address", "Name", numbers);

// Using the second constructor:
var human = new Human(1, "Address", "Name",
    new ContactNumber(1),
    new ContactNumber(2),
    new ContactNumber(3)
);

底线

哪种方案是最佳实践?或者至少是一个好的实践?你来评判!在我看来,最佳实践是尽可能清晰地编写程序,以便任何需要阅读它的人都能理解。在这种情况下,使用集合初始化器对我来说是一个胜利者。用更少的代码,它可以做到几乎与替代方案相同--至少是我给出的替代方案...


8
你是否正在寻找这个?
ContactNumbers = new List<ContactNumber>(){ new ContactNumber("555-5555"),
                                            new ContactNumber("555-1234"),
                                            new ContactNumber("555-5678") };

3
ContactNumbers = new List<ContactNumber>();

如果您希望将其传递进去,只需进行以下操作。
public Human(List<ContactNumber> numbers)
{
 ContactNumbers = numbers;
}

谢谢 @eouw0o83hf,很抱歉我没有解释得足够清楚。我想使用构造函数传递数字给list<ContactNubmer>。请问这样传递值到列表中是否是一个好的方法? - haansi
你是否在寻找 params 关键字 - TrueWill
不是TrueWill,我想使用构造函数给list<contactnumber>分配值。如果没有赋值,应该如何处理(默认值是什么)?这是一种标准的方式吗? - haansi
1
你可能想要发布你所需的调用代码。你想编写什么代码来创建一个人类? - TrueWill
请看一下我的第二个构造函数。这是一个好的方式吗?还是有什么需要改进的地方? - haansi
第二个构造函数很好。它会适当地设置属性。 - eouw0o83hf

3
您可以像初始化任何列表一样初始化它:
public List<ContactNumber> ContactNumbers { get; set; }

public Human(int id)
{
    Id = id;
    ContactNumbers = new List<ContactNumber>();
}

public Human(int id, string address, string name) :this(id)
{
    Address = address;
    Name = name;
    // no need to initialize the list here since you're
    // already calling the single parameter constructor
}       

然而,我认为可以更进一步并将setter设置为私有的,因为你通常不需要设置列表,只需要访问/修改其内容:

public List<ContactNumber> ContactNumbers { get; private set; }

谢谢@Lirik,能否指导如何从构造函数传递值到列表?同时请指导一下,将值传递给一个列表属性是否标准的构造函数使用方式? - haansi

1
通常不要公开暴露List<T>,也不要为集合属性提供setter。此外,您可能希望复制传递的列表元素(如下所示)。否则,对原始列表的更改将影响Human实例。
public class Human
{
    public Human()
    {
    }

    public Human(IEnumerable<ContactNumber> contactNumbers)
    {
        if (contactNumbers == null)
        {
            throw new ArgumentNullException("contactNumbers");
        }

        _contactNumbers.AddRange(contactNumbers);
    }

    public IEnumerable<ContactNumber> ContactNumbers
    {
        get { return _contactNumbers; }
    }

    private readonly List<ContactNumber> _contactNumbers = new List<ContactNumber>();
}

另一个选项是使用接受集合并删除字段初始化器的列表构造函数。

谢谢@TrueWill,我们可不可以像传递其他值一样通过构造函数传递一个列表,而不是先填充一个列表?如果没有值,则分配默认值。怎么做?这种方法可行吗? - haansi
1
这取决于你的需求。你正在传递一个引用。你想要在更改原始联系人列表时更改人类联系人吗?如果你想要一个默认列表,我通常会在Human中添加一个默认构造函数来创建一个空列表。尽可能避免使用空引用和特殊处理空列表。 - TrueWill

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