I can't seem to find any documentation on what new[] is supposed to be. From the example below it seems to be an object array shorthand
var json = new[] {
new object[] {"20-Jun-2008", 200 },
new object[] {"20-Jun-2009", 250 }
};
These are implicitly typed arrays.
See C# 3.0 specifications.
The syntax of array creation expressions (§7.5.10.2) is extended to
support implicitly typed array creation expressions:
array-creation-expression: ... new [ ] array-initializer
In an implicitly typed array creation expression, the type of the
array instance is inferred from the elements specified in the array
initializer. Specifically, the set formed by the types of the
expressions in the array initializer must contain exactly one type to
which each type in the set is implicitly convertible, and if that type
is not the null type, an array of that type is created. If exactly one
type cannot be inferred, or if the inferred type is the null type, a
compile-time error occurs.
The following are examples of implicitly typed array creation
expressions:
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { 1, 1.5, 2, 2.5 }; // double[]
var c = new[] { "hello", null, "world" }; // string[]
var d = new[] { 1, "one", 2, "two" }; // Error
The last expression causes a compile-time error because neither int
nor string is implicitly convertible to the other. An explicitly typed
array creation expression must be used in this case, for example
specifying the type to be object[]. Alternatively, one of the elements
can be cast to a common base type, which would then become the
inferred element type.
Implicitly typed array creation expressions can be combined with
anonymous object initializers to create anonymously typed data
structures. For example:
var contacts = new[] {
new {
Name = "Chris Smith",
PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
},
new {
Name = "Bob Harris",
PhoneNumbers = new[] { "650-555-0199" }
}
};
The notation is an implicitly typed array declaration.
In your case, it is a array of object arrays.
It means that new[] is an implicitly typed array. Since it's implicitly typed, you have to assign something to it as in this example. Just as you have to with the var keyword.
It's implicit typing. Since all the elements in that collection are object arrays, the compiler can deduce that the array itself must be a collection of object arrays.
Related
When writing my unit tests, I stumbled upon a problem: NUnit's [TestCaseAttribute], with the following constructor overloads:
public TestCaseAttribute(params object arg)
public TestCaseAttribute(params object args[])
would accept an array of integers, and a list of arguments including an array of strings, but would not accept an array of strings itself:
[TestCaseAttribute(new[] { 1, 2, 3 })] //works
[TestCaseAttribute("Other string", new[] { "1", "2", "3" })] //works
[TestCaseAttribute(new[] { "1", "2", "3" })] //compilation error?
This surprised me, so I verified the behavior:
private static void PrintTypes(params object[] objects)
{
Console.WriteLine("Array type is " + objects.GetType());
Console.WriteLine("Object count is " + objects.Length);
Console.WriteLine("Object type is " + objects[0].GetType());
}
public static void Main()
{
Console.WriteLine("Array of ints: ");
PrintTypes(new[] { 1, 2, 3 });
Console.WriteLine();
Console.WriteLine("Array of strings: ");
PrintTypes(new[] { "1", "2", "3" });
}
The output is somewhat baffling to me - it seems like the integer array is treated as a single object, but a string array is unrolled:
Array of ints:
Array type is System.Object[]
Object count is 1
Object type is System.Int32[]
Array of strings:
Array type is System.String[]
Object count is 3
Object type is System.String
And if we add the following method:
private static void PrintTypes(object obj)
{
Console.WriteLine("In object method");
Console.WriteLine("Object type is " + obj.GetType());
}
the compiler seems to prefer it for an array of ints, but not for an array of strings:
Array of ints:
In object method
Object type is System.Int32[]
Array of strings:
In array method
Array type is System.String[]
Object count is 3
Object type is System.String
Why is that the case? I'm assuming it has something to do with the integers not being reference types, but I'd like more of an explanation as to what exactly dictates that the compiler prefers different overloads for different arrays, and why one is allowable for the attribute constructor, but not the other.
You are on the right track with int not being a reference type being the reason for the observed behavior with your PrintTypes test method.
According to the C# specification (link), chapter 15.6.2.5
Parameter arrays:
A parameter array permits arguments to be specified in one of two ways
in a method invocation:
• The argument given for a parameter array can be a single expression that is implicitly convertible (§11.2) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.
Chapter 11.2 (Implicit reference conversions) explains what "implicitly convertible" means with respect to arrays:
The implicit reference conversions are:
[...]
• From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
- S and T differ only in element type. In other words, S and
T have the same number of dimensions.
- An implicit reference conversion exists from SE to TE
Note that the existence of an implicit reference conversion is a requirement here. A conversion from a value type to a reference type is not an (implicit) reference conversion (see chapter 11.2 again). This is the reason why the the int[] array is just being treated as a single object argument, which leads to PrintTypes being called in expanded form.
Now, why then is
[TestCaseAttribute(new[] { 1, 2, 3 })] //works
compiling, while
[TestCaseAttribute(new[] { "1", "2", "3" })] //compilation error?
is not? Does it not contradict what i just said?
Lets take a look at the constructors of TestCaseAttribute:
public TestCaseAttribute(params object[] arguments);
public TestCaseAttribute(object arg);
public TestCaseAttribute(object arg1, object arg2);
public TestCaseAttribute(object arg1, object arg2, object arg3);
From the explanation given above, it should be clear that [TestCaseAttribute(new[] { 1, 2, 3 })] is compiling, because it uses the TestCaseAttribute(object arg) constructor overload.
new[] { "1", "2", "3" } is a string array, and the compiler choses as best matching overload for this argument TestCaseAttribute(params object args[]) (according to the rules explained in chapter 12.6.4 Overload resolution). Unfortunately, the overload resolution does not take the special requirement for attributes into account that attribute arguments have to be constant expressions. The rules for constant expressions (chapter 12.20 Constant expressions) state:
Note: Other conversions including boxing, unboxing, and implicit
reference conversions of non-null values are not permitted in constant
expressions.
(emphasis mine)
And this is what leads to the compiler error with regard to the attribute. The compiler chooses a constructor overload it thinks best fits the string[] argument. Then, at a later stage of the compilation process the compiler is trying to apply the attribute. It notices that a required implicit reference conversion is not permitted for attribute arguments, which results in the observed compile error.
This question already has answers here:
What does "T" mean in C#?
(7 answers)
Closed 9 years ago.
public void DisplayValue<T>(T field, string fieldname)
What does T stands for in above code?
Whats the benefit to do so?
Where we can use this?
From Generics (C# Programming Guide)
... by using a generic type parameter T you can write a single class
that other client code can use without incurring the cost or risk of
runtime casts or boxing operations
It is a Generic Type Parameter.
A generic type parameter allows you to specify an arbitrary type T to a method at compile-time, without specifying a concrete type in the method or class declaration.
For example:
public T[] Reverse<T>(T[] array)
{
var result = new T[array.Length];
j=0;
for(int i=array.Length; i>= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}
reverses the elements in an array. The key point here is that the array elements can be of any type, and the function will still work. You specify the type in the method call; type safety is still guaranteed.
So, to reverse an array of strings:
string[] array = new string[] { "1", "2", "3", "4", "5" };
var result = reverse(array);Will produce a string array in result of { "5", "4", "3", "2", "1" }
This has the same effect as if you had called an ordinary (non-generic) method that looks like this:
public string[] Reverse(string[] array)
{
var result = new string[array.Length];
j=0;
for(int i=array.Length; i >= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}The compiler sees that array contains strings, so it returns an array of strings. Type string is substituted for the T type parameter.
Generic type parameters can also be used to create generic classes.
In the example you gave of a SampleCollection, the T is a placeholder for an arbitrary type; it means that SampleCollection can represent a collection of objects, the type of which you specify when you create the collection.
So:
var collection = new SampleCollection<string>();
creates a collection that can hold strings. The Reverse method illustrated above, in a somewhat different form, can be used to reverse the collection's members.
Type Parameters T: The type of elements in the list.
according to MSDN documentation.
Whats the benefit to do so?
The method can take anonymous lists of a type.
Where we can use this?
For example when the same manipulation has to be done on several lists of several types.
Array in C# is co-variant implicitly on reference type:
object[] listString = new string[] { "string1", "string2" };
But not on value type, so if you change string to int, you will get compiled error:
object[] listInt = new int[] {0, 1}; // compile error
Now, the concern is when you declare int array like two syntaxes below which do not explicitly declare the type int, just only differentiate on new[], compiler will treat differently:
object[] list1 = { 0, 1 }; //compile successfully
object[] list2 = new[] {0, 1}; //compile error
You will get object[] list1 = { 0, 1 }; compiled successfully, but object[] list2= new[] {0, 1}; compiled error.
It seems the C# compiler treats
object[] list1 = { 0, 1 };
as
object[] list1 = new object[]{ 0, 1 };
but
object[] list2 = new[] { 0, 1 };
as
object[] list2 = new int[]{ 0, 1 }; //error because of co-variant
Why C# compiler behaves in the different way on this case?
The version that compiles uses an array initializer to initialize list1. The C# language spec, §1.110 ("Array initializers") states:
An array initializer consists of a sequence of variable initializers,
enclosed by “{”and “}” tokens and separated by “,” tokens. Each
variable initializer is an expression or, in the case of a
multi-dimensional array, a nested array initializer.
The context in
which an array initializer is used determines the type of the array
being initialized. In an array creation expression, the array type
immediately precedes the initializer, or is inferred from the
expressions in the array initializer. In a field or variable
declaration, the array type is the type of the field or variable being
declared.
When an array initializer is used in a field or variable
declaration, such as:
int[] a = {0, 2, 4, 6, 8};
it is simply shorthand for an equivalent array creation expression:
int[] a = new int[] {0, 2, 4, 6, 8};
So it is obvious that this should compile.
The second version uses an explicit array creation expression, where you instruct the compiler specifically what type of array to create. §1.51.10.4 ("Array creation expressions") states:
An array creation expression of the third form is referred to as an
implicitly typed array creation expression. It is similar to the
second form, except that the element type of the array is not
explicitly given, but determined as the best common type (§1.50.2.14)
of the set of expressions in the array initializer.
Therefore, the second version is equivalent to
object[] list2 = new int[] { 0, 1 };
So the question now effectively becomes "why can I not assign an int[] to an object[]", just as you mention at the end of the question. And the answer is also simple, given in §1.109 ("Array covariance"):
Array covariance specifically does not extend to arrays of
value-types. For example, no conversion exists that permits an int[]
to be treated as an object[].
The declaration
object[] listInt = new int[] {0, 1};
is invalid because covariant array conversions are not allowed for value types (and int is a value type). Alternatively, the declaration
object[] listInt = new string[] {"0", "1"};
is valid because covariant array conversions are allowed for reference types. This is because the assignment x = (object)myString only involves a simple assignment, but y = (object)myInt requires a boxing operation.
Now on to the difference between the two declarations. In the declaration object[] list2 = new[] { 0, 1 }, due to how type inference works it first looks at the Right Hand Side expression and concludes that new[] { 0, 1 } should be treated as new int[] { 0, 1 }. Then it tries to assign this int array to an object array, giving an error because of the covariant conversion of value types issue. The declaration object[] list1 = { 0, 1 }, though, uses a collection initializer, and in those circumstances the type of the collection is where the type is defined, so each element will instead be cast to the type expected by the collection.
When you are using { and }, you use collection initializers (see: http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx). The values between those brackets will have to be put somewhere. Therefor a collection has to be created. The compiler will anaylize the context to find out what kind of collection.
In case the first: object[] list1 = { 0, 1 }; it is clear there should be a collection created. But what kind should it be? There is no new operation somewhere. There is only one hint: list1 is of type object[]. So the compiler creates that collection and fills it with the valiues.
In your second example object[] list1 = new[] { 0, 1 }; there is another hint: new[]. And this hint explicitly says: There is going to be an array. That array does not have a type, so it will try to find the type of the array by anaylizing the values. These are all int's so it will create an array of int's and fills it. The other hint object[] is totally ignored because hints of creation are much more important than hints where it should be assigned to. Now the compiler wants to assign this array to list1 and BOOM: that does not fit!
The statement object[] list1 = { 0, 1 }; compiles because the compiler is smart enough to know you are attempting to convert an array of numeric types to a reference-type array, so it boxes the Int32 elements into reference types.
You could also explicitly box the primitive type:
object[] list2 = Array.ConvertAll<int, Object>(new[] { 0, 1 }, input => (Object)input);
The compiler will not implicitly do the boxing for you when you have specified 'int[]' or 'Int32[]' as the array type, but it seems like this could be added to C#.
An array initialiser is a compiler convenience. If I say "I am declaring an array of objects and assigning it a value," it is reasonable for the compiler to assume that your { 0, 1 } is an object array and interpret it as such. Although the syntax appears to be an assignment, it is not: you're using an initialiser. The longhand for this syntax is object[] list1 = new object[] { 0, 1 }
When you say new[] { 0, 1 }, this is an expression that creates an array and initialises it. This expression is evaluated independently of what you're assigning it to - and because the compiler detects the implicit integer typing, it creates an int[]. The longhand version of that expression is object[] list2 = new int[] { 0, 1 }
If you compare the longhand versions of these two statements, it's clear to see where they differ.
object[] listInt = new int[] {0, 1};
is shorthand for
object[] listInt;
listInt = new int[] {0, 1};
which doesn't work because int[] is not covariant with object[].
And when you say new[], it is equivalent to new int[], hence the same applies.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is this new[] a shorthand for?
Is there any difference between
var strings = new string[] { "hello", "world" };
and
var strings2 = new[] { "hello", "world" };
In this case, no difference, as new[] will infer the provided values type as string.
See Implicitly typed arrays.
No difference.
The second one is a syntactic-sugar called "Implicitly typed arrays", and both the expressions return an array of strings.
When you don't specify the type of the array, it is inferred from the types of the elements used to initialize the array.
To allow the inference, the expression must satisfy the following condition:
Considering an implicitly typed array expression like this:
var arr = new []{ obj1, ... , objn }
and the set of all the types of the elements in the initialization being:
S = {T1, ..., Tn}
to allow the inference (i.e. no compiler error) it must be possible for all the types { T1, ... , Tn } to be implicitly cast to one of the types in the set S.
So, for example, given the following classes:
class Base { }
class Derived1 : Base { }
class Derived2 : Base { }
class Derived3
{
public static implicit operator Base(Derived3 m)
{ return null; }
}
This code compiles:
var arr = new []{ new Derived1(), new Derived2(), new Derived3(), new Base()};
while the following does not:
var arr = new []{ new Derived1(), new Derived2(), new Derived3() };
since in the first case all the 3 types can be implicitly cast to type Base, and Base type is inside the set S = { Derived1, Derived2, Derived3, Base }, while in the second case all the types cannot be cast to one type in the set S = { Derived1, Derived2, Derived3 }
This feature has been introduced with C# 3.0 along with anonymous types and it makes instantiation of arrays of the latter easier.
For instance, this would be really hard to obtain without implicitly typed arrays:
var arrayOfAnonymous = new[] { new { A = 3, B = 4 }, new { A = 2, B = 5 } };
In this case, there is no difference. Because of hello and world are string;
var strings2 = new[] { "hello", "world" };
creates a string[] array which is the same with first one.
Second one is just called Implicitly Typed Arrays
If we go one step further, they have the same IL code.
None, the compile interprets it as new string[] { "hello", "world" };
It's just like using var, the compiler handles what you meant.
new[] creates an implicitly typed array in which the type is infered from the elements. while the other approach creates an array of string.
There is no difference.
In the 2nd case, the C# compiler is smart enough to infer the type of the array, since it sees that the values that are used to initialize the array, are of type string.
I have a field that is of type 'object'. When I inspect it within the Watch window of visual studio I see its Object[] and when I drill into the elements I see each element is a string.
But when I try to cast this to a String[] I get this error:
Cannot cast 'MyObject' (which has an actual type of 'object[]') to 'string[]' string[]
Any reason why I can't do this cast? What is the best way to convert this object to a string array?
This is a particularly confusing feature of C#. Here's the deal.
Throughout this discussion we assume that the element type of an array is a reference type, not a value type.
C# supports unsafe array covariance. That means that if you have an array of string, you can convert it to an array of object, because a string can be converted to an object:
string[] a1 = { "hello", "goodbye" };
object[] a2 = a1; // Legal
If you then try to get an element out of a2, it works:
object o3 = a2[0];
That's legal because a2[0] is really a1[0], which is a string, which is convertible to object.
However, if you attempt to write to the array then you'll get an error at runtime:
a2[0] = new object();
This fails at runtime because a2 is really an array of strings, and you can't put a non-string into an array of strings.
So C# is already horribly broken; it is possible to write a program that compiles and looks normal but suddenly crashes with a type exception at runtime because you tried to put an object into an array of objects that is not actually an array of objects.
The feature you want is even more broken than that, and thank goodness C# does not support it. The feature you want is:
object[] a4 = { "Hello" };
string[] a5 = a4;
That would be unsafe array contravariance. It breaks horribly like this:
a4[0] = new Customer(); // Perfectly legal
string s6 = a5[0];
And now we just copied a Customer into a variable of type string.
You should avoid any kind of array covariance or contravariance; array contravariance is, as you've discovered, not legal, and array covariance is making little time bombs in your program that go off unexpectedly. Make your arrays of the right type to begin with.
string[] newarr = Array.ConvertAll(objects, s => (string)s);
--EDIT--
since you've said I have an object (knowing that it is an object[] actually)
string[] newarr = Array.ConvertAll((object[])objects, s => (string)s);
object[] original = new object[]{"1", "2"};
//some code in between here
object obj = original ;
object[] objArray = (object[])obj;
string[] newArray = new string[objArray.Length];
for(int i = 0; i < newArray; i++)
{
newArray[i] = (string)objArray[i];
}
Other answers here are showing you quicker/shorter ways of doing the conversion. I wrote the whole thing out like this because it shows what's really going on and what needs to happen. You should use one of the simpler methods in your actual production code.
The rule in object oriented programming is -
"Derived class can always be type casted to base class" AND
"A Base class can be casted to derived class only if the current instance that base class hold off is actually derived class"
e.g. (A is base and B is derived)
A a = new B(); // legal;
B b = (B) a ; // legal as "a" is actually B (in first statement)
illegal : >
A a = new A();
B b = (B) a; // not legal as "a" is A only.
Same thing is applied to Object and String classes. Object is base class and string is Derived class.
You can convert the real string[] to object[].
This is a Array covariance
Can find a clear example in link.
You should cast each element in the collection and not the collection itself.
object[] ovalues = new object[] { "alpha", "beta" };
string[] svalues = ovalues.Cast<string>().ToArray();