41

I have a type:

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;
    }        
}

Please guide me is among best practices to use constructor with for list initialization? How to initialize a list using constructor?

Edit:

Please guide me is among best practices to use constructor with for list initialization? How to assign values to list using a constructor, so if no value passed a default will be used?

Thanks

joce
  • 9,624
  • 19
  • 56
  • 74
haansi
  • 5,470
  • 21
  • 63
  • 91

5 Answers5

67

Using a collection initializer

From C# 3, you can use collection initializers to construct a List and populate it using a single expression. The following example constructs a Human and its ContactNumbers:

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

Specializing the Human constructor

You can change the constructor of the Human class to provide a way to populate the ContactNumbers property:

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)
);

Bottom line

Which alternative is a best practice? Or at least a good practice? You judge it! IMO, the best practice is to write the program as clearly as possible to anyone who has to read it. Using the collection initializer is a winner for me, in this case. With much less code, it can do almost the same things as the alternatives -- at least, the alternatives I gave...

Humberto
  • 7,117
  • 4
  • 31
  • 46
8

Are you looking for this?

ContactNumbers = new List<ContactNumber>(){ new ContactNumber("555-5555"),
                                            new ContactNumber("555-1234"),
                                            new ContactNumber("555-5678") };
joce
  • 9,624
  • 19
  • 56
  • 74
3
ContactNumbers = new List<ContactNumber>();

If you want it to be passed in, just take

public Human(List<ContactNumber> numbers)
{
 ContactNumbers = numbers;
}
eouw0o83hf
  • 9,438
  • 5
  • 53
  • 75
  • Thanks @eouw0o83hf, I am sorry for my not enough explaination. I want to pass numbers for list using constructor. Kindly also tell is it a good way to pass values to list just like we pass other values ? – haansi Jan 31 '12 at 23:31
  • Are you looking for the [params keyword](http://msdn.microsoft.com/en-us/library/w5zay9db.aspx)? – TrueWill Jan 31 '12 at 23:43
  • No TrueWill, I want to assign values to list using constructor. Please also guide how to handle if no values is assign (what would be default) ? Is it a standard way ? – haansi Jan 31 '12 at 23:47
  • 1
    You might want to post your desired calling code. What code do you want to write to create a Human? – TrueWill Jan 31 '12 at 23:49
  • TrueWill please see my 2nd constructor. Is it a good way ? or how it should be improved ? – haansi Jan 31 '12 at 23:53
  • The second constructor is good. It will appropriately set the property – eouw0o83hf Jan 31 '12 at 23:56
3

You can initialize it just like any list:

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
}       

However, I would even go a step further and make the setter private since you often don't need to set the list, but just access/modify its contents:

public List<ContactNumber> ContactNumbers { get; private set; }
Kiril
  • 39,672
  • 31
  • 167
  • 226
  • Thanks @Lirik, Kindly guide how to pass values to list from constrcot ? also guide is it standard way to use constroctor to pass values to a property which is a list basically ? – haansi Jan 31 '12 at 23:34
1

In general don't expose List<T> publicly, and don't provide setters for collection properties. Also, you may want to copy the elements of the passed list (as shown below). Otherwise changes to the original list will affect the Human instance.

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>();
}

Another option is to use the list constructor that takes a collection and remove the field initializer.

TrueWill
  • 25,132
  • 10
  • 101
  • 150
  • Thanks @TrueWill, can we not fill a list and pass it to constructor just as we pass other values through constructor and if there is no values then assign a default ? how it will be done ? Is it a good way to do so ? – haansi Jan 31 '12 at 23:36
  • 1
    It depends. You're passing a **reference**. Do you want the Human's contacts to change when the original contact list is changed? If you want a default list I'd normally add a default constructor to Human that would create an empty list. Avoid null references whenever possible. Also avoid special-casing empty lists. – TrueWill Jan 31 '12 at 23:41