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: