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.
Related
I am new to anonymous types in c#, and I want to create a list of anonymous types that contain 3 variables: string str, int num, DataTime time.
however, when I try to use the code from this question`s answers: A generic list of anonymous class
it won't work for me.
I used a simple Console application to do it and I think I get the error
because I don't have System.Core because someone in the comment of the question above said that:
(You also need a reference to System.Core of course.)
and I don't know what is System.Core and if I have it so it might be the problem
I do use Systme.Linq.
here is the code:
var list = new[] { str, num, time }.ToList();
list.add("hi", 5, DateTime.Now);
Console.WriteLine(list[0].num);
I also face issues when I try to specify the type of the variables
for example string str.
You are missing some syntax. Anonymous types must be declared with new{...}. The property names must be declared when they cannot be inferred by a variable name. (You also have a typo in Add; it should be uppercase).
The below works:
var str = "string";
var num = 5;
var time = DateTime.UtcNow;
// notice double "new"
// property names inferred to match variable names
var list = new[] { new { str, num, time } }.ToList();
// "new" again. Must specify property names since they cannot be inferred
list.Add(new { str = "hi", num = 5, time = DateTime.Now });
Console.WriteLine(list[0].num);
With that said, this is pretty clunky. I'd suggest writing a class with the properties you want, or using ValueTuple.
This works and is clearer/cleaner:
var list = new List<(string str, int num, DateTime time)>();
// ValueTuple are declared in parens, method calls require parens as well
// so we end up with two sets of parens, both required
list.Add((str, num, time));
list.Add(("hi", 5, DateTime.Now));
Console.WriteLine(list[0].num);
Another reason to prefer your own class or ValueTuple is that you cannot declare a method as accepting an anonymous type. In otherwords, something like this is not valid:
public void DoSomethingWithAnonTypeList(List<???> theList ) { ... }
There is nothing* I can put to replace the ??? as anonymous types are both internal and have "unspeakable" names. You wouldn't be able to pass your list around and do something meaningful with it. So what's the point?
Conversely, I can declare a method as accepting a list of ValueTuples:
public void DoSomethingWithTupleList(List<(string, int, DateTime)> theList) {
Console.WriteLine(theList[0].Item1);
}
or using named tuples:
public void DoSomethingWithTupleList(List<(string str, int num, DateTime time)> theList) {
Console.WriteLine(theList[0].time);
}
* You can technically pass your list of anonymous types to a generic method. However you won't be able to access the individual properties. The best you'd be able to do is access the list's Count or iterate over the list/enumerable and perhaps print the default ToString which doesn't really get you much either. There's not a generic constraint to help here. The third statement in this method will generate a compiler error:
public void DoSomethingGenerically<T>(List<T> theList) {
Console.WriteLine(theList.Count); // valid
Console.WriteLine(theList[0]); // valid, prints default ToString
Console.WriteLine(theList[0].num); // invalid! What's the point?
}
var list = new[] { new { str = "hi", num = 5, time = DateTime.Now } }.ToList();
// valid due to type inference, but see comments above
DoSomethingGenerically(list);
Do note that you'll have the same issue with ValueTuple, I'm just clarifying my "do nothing" statement.
Let's say I have the following classes
public class Dog{}
public class Bulldog : Dog{}
public class Pitbull : Dog{}
I am trying to create a list like this
var dogs2 = new[]
{
new { X = new Bulldog(), Y = 10},
new { X = new Pitbull(), Y = 20}
}.ToList();
But, I am getting the following error No best type found for implicitly - typed array
Ok, I guess that makes sense. The system can't figure out that X is a type ofDog`
So, I try doing this
var dogs1 = Enumerable.Empty<object>()
.Select(x => new { X = new Dog (), Y = 0 })
.ToList();
dogs1.Add(new { X = new Pitbull(), Y = 10 });
dogs1.Add(new { X = new Bulldog(), Y = 10 });
Now, I am getting this error cannot convert from '<anonymous type: PassingEvents.Bulldog X, int Y>' to '<anonymous type: PassingEvents.Dog X, int>'. Why can't it convert? Isn't Bulldog castable to Dog?
Is there a way to fix this, without having to crate a new class? The code below works just fine
public class DogCombo
{
public Dog X;
public int Y;
}
var dogs3 = new[]
{
new DogCombo{ X = new Bulldog(), Y = 10},
new DogCombo{ X = new Pitbull(), Y = 20}
}.ToList();
Why can't it convert? Isn't Bulldog castable to Dog?
Bulldog is convertible to Dog, yes.
Your reasoning is as follows:
Bulldog is convertible to Dog
Therefore anonymous-type-with-Bulldog should be convertible to anonymous-type-with-Dog.
This reasoning -- that the properties of the underlying types should imply properties of types under a transformation -- is called covariance.
C# supports covariance in certain restricted cases. They are:
An array of Bulldog may be used as an array of Dog. Note that this is unsafe covariance, because you can put a Poodle into an array of Dog, but not into an array of Bulldog. Array covariance is only safe if you never write to the array.
An IEnumerable<Bulldog> may be converted to IEnumerable<Dog>. This is safe. A sequence of bulldogs is a sequence of dogs. This is also true of a few other generic types, like IEnumerator<T>.
A method which returns a Bulldog may be converted to a delegate for a delegate type that returns a Dog.
C# also supports contravariance in some cases. For example, an IComparable<Dog> may be converted to IComparable<Bulldog>. A thing which can compare dogs can compare bulldogs. Note that this convertibility is going in the opposite direction, hence contra variant.
C# does not support any covariance (or contravariance) on classes, structs or anonymous types.
In theory, C# could support contravariance on anonymous types as you desire; it would be safe to do so. The language and runtime teams have been pitched this feature before. It's simply the case that the language and runtime teams have not prioritized the feature highly enough to actually implement it.
If you think that there is a really good reason to implement covariant conversions on structural types like anonymous types, you can start a discussion on that topic on the Roslyn github forum, and maybe it will be implemented someday.
Is there a way to fix this, without having to create a new class?
I would suggest that you create a new class. But if you want a cheap and easy workaround: just cast explicitly to Dog.
You can explicitly cast X to a type of Dog:
var dogs2 = new[]
{
new { X = (Dog)new Bulldog(), Y = 10},
new { X = (Dog)new Pitbull(), Y = 20}
}.ToList();
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.
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();
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.