C# 6 adds a new feature just for this: extension Add methods. This has always been possible for VB.net but is now available in C#.
Now you don't have to add Add()
methods to your classes directly, you can implement them as extension methods. When extending any enumerable type with an Add()
method, you'll be able to use it in collection initializer expressions. So you don't have to derive from lists explicitly anymore (as mentioned in another answer), you can simply extend it.
public static class TupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
T1 item1, T2 item2)
{
list.Add(Tuple.Create(item1, item2));
}
public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list,
T1 item1, T2 item2, T3 item3)
{
list.Add(Tuple.Create(item1, item2, item3));
}
// and so on...
}
This will allow you to do this on any class that implements IList<>
:
var numbers = new List<Tuple<int, string>>
{
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 4, "four" },
{ 5, "five" },
};
var points = new ObservableCollection<Tuple<double, double, double>>
{
{ 0, 0, 0 },
{ 1, 2, 3 },
{ -4, -2, 42 },
};
Of course you're not restricted to extending collections of tuples, it can be for collections of any specific type you want the special syntax for.
public static class BigIntegerListExtensions
{
public static void Add(this IList<BigInteger> list,
params byte[] value)
{
list.Add(new BigInteger(value));
}
public static void Add(this IList<BigInteger> list,
string value)
{
list.Add(BigInteger.Parse(value));
}
}
var bigNumbers = new List<BigInteger>
{
new BigInteger(1), // constructor BigInteger(int)
2222222222L, // implicit operator BigInteger(long)
3333333333UL, // implicit operator BigInteger(ulong)
{ 4, 4, 4, 4, 4, 4, 4, 4 }, // extension Add(byte[])
"55555555555555555555555555555555555555", // extension Add(string)
};
C# 7 will be adding in support for tuples built into the language, though they will be of a different type (System.ValueTuple
instead). So to it would be good to add overloads for value tuples so you have the option to use them as well. Unfortunately, there are no implicit conversions defined between the two.
public static class ValueTupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
ValueTuple<T1, T2> item) => list.Add(item.ToTuple());
}
This way the list initialization will look even nicer.
var points = new List<Tuple<int, int, int>>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
But instead of going through all this trouble, it might just be better to switch to using ValueTuple
exclusively.
var points = new List<(int, int, int)>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
Dictionary
doesn't allow duplicate keys. – Submersible