I was curious if I could enhance the standard generic List<> functionality because I was fed up with writing code such as:
var list = new List<Person>{
new Person{Name = "David", Age = 24},
new Person{Name = "John", Age = 30}
};
list.Add(new Person{Name = "Terry", Age = 28});
I’d prefer that T could be implicitly constructed. The best I came up with allowed me to do this with up to four object construction parameters:
var list = new ListWithConstructor<string, int, Person>(
(name,age) => new Person { Name = name, Age = age })
{
{"David", 24},
{"John", 30}
};
list.Add("Terry", 28);
This is implemented like this:
public class ListWithConstructor<T1, T> : List<T>
{
private readonly Func<T1, T> itemConstructor;
public ListWithConstructor(Func<T1, T> itemConstructor)
{
this.itemConstructor = itemConstructor;
}
public void Add(T1 arg1)
{
base.Add(itemConstructor(arg1));
}
}
public class ListWithConstructor<T1, T2, T> : List<T>
{
private readonly Func<T1, T2, T> itemConstructor;
public ListWithConstructor(Func<T1, T2, T> itemConstructor)
{
this.itemConstructor = itemConstructor;
}
public void Add(T1 arg1, T2 arg2)
{
base.Add(itemConstructor(arg1, arg2));
}
}
…and so on for up to four arguments.
Obviously the other List<> constructors (taking a capacity and an IEnumerable of existing elements) can be implemented as well.
How can this be improved?
The functionality that you are looking for is (almost) already available at your fingertips:
This way you also have a clear separation of concerns; the
Listis not at all involved in the object construction (not even by just invoking a delegate), but is simply assigned a sequence of objects. The transformation is taken care of separately.This can also handle the case of transforming multiple values into single objects:
In the case of merging values from exactly two lists into single objects, using
Zipmight give slightly cleaner code;