My goal is to create a List of pairs (of ONLY type double). For example: { {1.0,1.1}, {1.2,1.3}, {1.4,1.5}, {...}, {...} } where {1.0,1.1} is List[0], {1.2,1.3} is List[1], {1.4,1.5} is List[2], et cetera.
RATION ERROR
Tuple<double,double> a1 = new Tuple<double,double>(1.0, 1.1);
Tuple<double,double> a2 = new Tuple<double,double>(1.2, 1.3);
Tuple<double,double> a3 = new Tuple<double,double>(1.4, 1.5);
//List< Tuple<double,double> > a4 = new List< Tuple<double, double> >(a1, a2, a3); //ERROR
List< Tuple<double,double> > a5 = new List< Tuple<double, double> >{a1, a2, a3}; //COMPILES
List< Tuple<double,double> > a6 = new List< Tuple<double, double> >(){a1, a2, a3}; //COMPILES
//List< Tuple<double,double> > a7 = new List< Tuple<double, double> >{a1, a2, a3}(); //ERROR
- In a4, a5, a6, and a7, why are the () optional but the {} are not?
- In a4, why can I not use () for instantiating the List<>, considering the () is made for instantiation arguments?
- Does 2. have the same reasoning as the error when trying to instantiate a7?
I know that [] always indicates selecting an element in an array, hence why I didn't try that.
Also, I am aware of ValueTuple but I want compatibility with previous versions of C# and/or .NET (idk the difference) and Tuple is not significantly more amazing than ValueTuple.
CodePudding user response:
When you use { a1, a2, a3 } you're using the collection initializer. In this situation, you don't necessarily have to add () to call the parameterless constructor of the collection. That's why new List<int>() { 1 } would work just as well as new List<int> { 1 }.
A more complex example might be to specify the initial capacity (not number of items) of the list, and add fewer items: new List<int>(5) { 1, 2, 3 }. This would give us a list with 3 items in it, but with a capacity of 5 (so it doesn't need to internally resize its arrays until we try to add a 6th item).
As for why new List<int>(1, 2, 3) wouldn't work: there simply isn't a constructor that accepts items in this format.
Consider these two methods:
public static void Test1(int[] items)
{
}
public static void Test2(params int[] items)
{
}
We can call Test1 as Test1(new int[] { 1, 2, 3 }) but not as Test1(1, 2, 3). Because Test2 has the params keyword, we can call it both as Test2(new int[] { 1, 2, 3 }) and Test2(1, 2, 3). It's the params keyword that does the magic here.
Now, the following list constructors are available:
public List ();- this doesn't take any parameters, and is what we use when we writenew List<int> { 1 }(implicit) ornew List<int>() { 1 }(explicit).public List (System.Collections.Generic.IEnumerable<T> collection);- this allows you to pass any object that implementsIEnumerable<T>. This is whynew List<int>(new int[] { 1, 2, 3 })works. Arrays (int[]) implementIEnumerable<T>, as do lists, queues, dictionaries, and all sorts of other collection types.public List (int capacity);- This just sets the capacity, and is what we use if we callnew List<int>(5) { 1, 2, 3 };
There is no constructor that accepts params T[], so we simply can't construct a list like new List<int>(1, 2, 3);.
Documentation:
