Covariance/Conversion issue with Generics - c#

Consider the code:
using System.Collections.Generic;
namespace TestingTypes
{
class Program
{
static void Main(string[] args)
{
var strings = new List<string>();
INeedToPassThisMethodAListOfObjects(strings as List<object>);
}
static void INeedToPassThisMethodAListOfObjects(List<object> objects) { }
}
}
1>------ Build started: Project: TestingTypes, Configuration: Debug Any CPU ------
1>c:\users\[censored]\TestingTypes\Program.cs(9,41,9,64): error CS0039: Cannot convert
type 'System.Collections.Generic.List<string>' to
'System.Collections.Generic.List<object>' via a reference conversion, boxing
conversion, unboxing conversion, wrapping conversion, or null type conversion
You might say that a List<string> is a List<object>, since a string is an object and C# 4 is supposed to support covariance in generic types.
Why does the compiler say it can't convert the type?
How do I pass "strings" to the method?

Interfaces can be variant; classes cannot. See here for the explanation.
Your code will work if you pass the strings collection uncasted and change the declaration to be
static void INeedToPassThisMethodAListOfObjects(IEnumerable<object> objects) { }
However, that depends on whether you need a List within this function.

You're getting the error because a List<string> is not a List<object>.
You can call list.Add(new TextBox()) on List<object> but, obviously, the same call doesn't work on List<string>.
C# Generics only allow for Covariance if the generic type is immutable (which is my the cast from List to IEnumerable works).
If you need to pass the list to a method, you could try passing
listOfStrings.Cast<object>();
On the downside, if you use that solution, any modifications made to the list inside the method call will not be reflected in the original list (because the call to Cast creates a new list).
If you have control of the method INeedToPassThisMethodAListOfObjects and that method only needs to iterate over the collection rather than modify it, you can change the parameter type to be IEnumerable<object> in which case you'd simply be able to pass your List<string> without any issues.

You have to convert the strings to objects. Theres a nice LINQ method to do so.
var strings = new List<string>();
INeedToPassThisMethodAListOfObjects(strings.Cast<object>());
Edit
According to your own link,
In C#, variance is supported in the following scenarios:
Covariance in arrays (since C# 1.0)
Covariance and contravariance in delegates, also known as “method group variance” (since C# 2.0)
Variance for generic type parameters in interfaces and delegates (since C# 4.0)
So IEnumerable would accept List

Related

Cannot Cast Generic Primitive with dynamic C#

I am trying to check if a result, which I downcast in the return type is convertible to which derived type. The derived type I am checking against is a generic with a covariant argument. I am using the is operator to cast it to a dynamic type. I believe since the generic argument is a primitive type bool that it is not working. Strangely in the watch window the result is as expected, but the code execution is not. I'm not sure if there is something i'm missing or this is a bug. Is this expected behavior?
I have worked around this by checking if the result is a generic and then getting the type argument and using MakeGenericType combined with a 'dynamic result = Convert.ChangeType'.
Here is a simple sample application to demonstrate.
var testBool = new List<bool>(); // Primitive
var testString = new List<string>(); // Class
if (testBool is IEnumerable<bool>)
Console.WriteLine("Test Bool");
if (testBool is IEnumerable<dynamic>)
Console.WriteLine("Test Bool - Dynamic");
if (testString is IEnumerable<string>)
Console.WriteLine("Test string");
if (testString is IEnumerable<dynamic>)
Console.WriteLine("Test string - Dynamic");
Notes: .NET Core 2.1, Visual Studio 2017, C#
dynamic doesn't exist at execution time as a distinct type. Dynamic typing is performed by the C# compiler in conjunction with some very cunning framework features. The runtime doesn't know about it at all though.
You're effectively asking whether testBool implements IEnumerable<object> - and it doesn't. (That's what the IL involved is testing for.)
There is a bug, but it's in the Watch window handling - not in the regular execution. I've seen various situations where the Watch window doesn't quite behave like regular code. I wouldn't be surprised if this was particularly acute around dynamic.
In terms of the behaviour of the List<string>:
List<string> implements IEnumerable<dynamic> due to the covariance of IEnumerable<T> (i.e. it implements IEnumerable<object>)
List<string> doesn't implement IList<dynamic>, as just one example where there's no variance involved.
If you were thinking that using dynamic as a type argument would effectively check "does this type implement IEnumerable<T> for some type T which will be determined dynamically", it doesn't. You can use dynamic to perform execution-time type inference though:
dynamic d = ...; // Whatever value you're interested in
ShowList(d);
private void ShowList<T>(IEnumerable<T> list)
{
Console.WriteLine($"Implements IEnumerable<{typeof(T)}>");
}
private void ShowList(object backstop)
{
Console.WriteLine("I guess it doesn't implement IEnumerable<T> at all");
}
Note that this sort of thing can be dangerous if you're dealing with entirely unknown values - if you try this with a value that implements (say) IEnumerable<string> and IEnumerable<bool>, an exception will be thrown in the same way that you'd get a compile-time error trying to call ShowList with that value, as type inference doesn't find a "best" T.

Why does ToList<Interface> not work for value types?

If I implement an interface for a value type and try to cast it to a List of it's interface type, why does this result in an error whereas the reference type converts just fine?
This is the error:
Cannot convert instance argument type
System.Collections.Generic.List<MyValueType> to
System.Collections.Generic.IEnumerable<MyInterfaceType>
I have to explicitely use the Cast<T> method to convert it, why?
Since IEnumerable is a readonly enumeration through a collection, it doesn't make any sense to me that it cannot be cast directly.
Here's example code to demonstrate the issue:
public interface I{}
public class T : I{}
public struct V: I{}
public void test()
{
var listT = new List<T>();
var listV = new List<V>();
var listIT = listT.ToList<I>(); //OK
var listIV = listV.ToList<I>(); //FAILS to compile, why?
var listIV2 = listV.Cast<I>().ToList(); //OK
}
Variance (covariance or contravariance) doesn't work for value types, only reference types:
Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type. (MSDN)
The values contained inside reference type variables are references (for example, addresses) and data addresses have the same size and are interpreted the same way, without any required change in their bit patterns.
In contrast, the values contained inside value type variables do not have the same size or the same semantics. Using them as reference types requires boxing and boxing requires type-specific instructions to be emitted by the compiler. It's not practical or efficient (sometimes maybe not even possible) for the compiler to emit boxing instructions for any possible kind of value type, therefore variance is disallowed altogether.
Basically, variance is practical thanks to the extra layer of indirection (the reference) from the variable to the actual data. Because value types lack that layer of indirection, they lack variance capabilities.
Combine the above with how LINQ operations work:
A Cast operation upcasts/boxes all elements (by accessing them through the non-generic IEnumerable, as you pointed out) and then verifies that all elements in a sequence can be successfully cast/unboxed to the provided type and then does exactly that. The ToList operation enumerates the sequence and returns a list from that enumeration.
Each one has its own job. If (say) ToList did the job of both, it would have the performance overhead of both, which is undesirable for most other cases.

How can I use list that created using reflection as normally create list

I created a list using method from this post
Create list of variable type
Assembly assembly = Assembly.Load("ConsoleApplication4");
Type mytype = assembly.GetType("ConsoleApplication4.TestClass");
Type genericList = typeof(List<>).MakeGenericType(mytype);
var mylist = Activator.CreateInstance(genericList);
my question is,after I create the list, how can I use the list in a function like following:
public void TestFunction<T>(List<T> mylist)
{
//do something here
}
You'd lose static type analysis and compile-time checking (then again, given that you're working with reflection that's already happened), so you could just re-write your TestFunction as:
public void TestFunction(dynamic myList)
{
// do something here
}
you could simply change the last line where you instantiate the list
dynamic mylist = Activator.CreateInstance(genericList);
That way the compiler won't try to infer the (runtime) type of myList but will defer this task to the DLR which in your case will be happy to tell you that it is some List<mytype>
If you at some point know the concrete type of mylist you can of course also use a simple cast
TestFunction((List<knownType>)mylist);
which one to prefer is mainly a matter of taste, there might be performance differences between the two but compared to the reflection based instantiation that difference is probably not going to be the bottleneck but if performance is of main concern use a profiler.
The reason why I suggest using dynamic at the instantiation site instead of in the method signature is to make most of the code statically typed so that the compiler can check most of the code. By using dynamic in the method signature you will make all calls of that method into dynamic calls whereas if you make the mylist dynamically typed you are only make the statements using mylist into dynamic calls.
You can not use the instance of mylist in the way you want, because the Compiler can not infer the closed type of List. You can only work with further reflection methods or inspect it with open generic types.

Nested generics with IDictionary and IEnumerable

In a generic C# class for an internal reusable library, I'd like to pass a reference to "something that maps to a list of other things". The data types of what is passed in there are not supposed to be known by the library. Also, the way they are stored should not be known either, i.e. what is today a list that is held in memory, might later be a database table that is read from on demand.
So I thought I'd write this library class:
class GenericClass<T, U>
{
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
// do something
}
}
This compiles, but trying to pass in concrete implementations does not:
class UsingClass
{
public static void Main(string[] args)
{
var c = new GenericClass<string, string>();
c.Foo(new Dictionary<string, List<string>>());
}
}
I'm getting the following two syntax errors:
Filename.cs(46,13): error CS1502: The best overloaded method match for 'GenericClass<string,string>.Foo(System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>)' has some invalid arguments
Filename.cs(46,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.Dictionary<string,System.Collections.Generic.List<string>>' to 'System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>'
Replacing the IEnumerable on the declaration of Foo() with List fixes it, but that's of course not quite what I want.
Is this really not supported by C# (4.0) or am I just missing something obvious? What workaround would you suggest? (I'm sure this has been talked about before a lot, so links to great descriptions are fine, too.)
Yes, I should be able to write my own helper classes for that, but why do I have to?
Yes, this is really not supported. Imagine your Foo method looked like this:
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
T key = GetKeyFromSomewhere();
bar[key] = new U[10]; // Create an array
}
That looks okay, doesn't it? We can convert from U[] to IEnumerable<U>.
It's not so good from the caller's point of view though - suddenly we've got a string[] reference value in the dictionary, when all the values are meant to be List<string> references! Bang goes type safety.
You can rewrite the method as:
public void Foo<TValue>(IDictionary<T, TValue> bar)
where TValue : IEnumerable<U>
That will let you get values out of the dictionary and convert them to IEnumerable<U> implicitly... but you'd only be able to put exactly the right type of value into the dictionary, and you can't build that just from a U value.
As of version 4, C# supports generic variance in restricted circumstances. So for example, this works in C# 4 (when targeting .NET 4) but previously wouldn't:
List<string> strings = new List<string>();
IEnumerable<object> objects = strings;
For a lot more on generic variance, see Eric Lippert's blog series on the topic. Be prepared for your brain to explode periodically.

What is the "< >" syntax within C#

I have been learning about the basics of C# but haven't come across a good explanation of what this is:
var l = new List<string>();
I don't know what the <string> is doing or if it's the List that is doing the magic. I have also seen objects been thrown within the < > tags.
Can someone explain this to me with examples, please?
That is the generic syntax for C#.
The basic concept is that it allows you to use a Type placeholder and substitute the actual real type in at compile time.
For example, the old way:
ArrayList foos = new Arraylist();
foos.Add("Test");
worked by making ArrayList store a list of System.Objects (The base type for all things .NET).
So, when adding or retrieving an object from the list, The CLR would have to cast it to object, basically what really happens is this:
foos.Add("Test" as System.Object);
string s = foos[1] as String.
This causes a performance penalty from the casting, and its also unsafe because I can do this:
ArrayList listOfStrings = new ArrayList();
listOfStrings.Add(1);
listOfStrings.Add("Test");
This will compile just fine, even though I put an integer in listOfStrings.
Generics changed all of this, now using Generics I can declare what Type my collection expects:
List<int> listOfIntegers = new List<int>();
List<String> listOfStrings = new List<String>();
listOfIntegers.add(1);
// Compile time error.
listOfIntegers.add("test");
This provides compile-time type safety, as well as avoids expensive casting operations.
The way you leverage this is pretty simple, though there are some advanced edge cases. The basic concept is to make your class type agnostic by using a type placeholder, for example, if I wanted to create a generic "Add Two Things" class.
public class Adder<T>
{
public T AddTwoThings(T t1, T t2)
{
return t1 + t2;
}
}
Adder<String> stringAdder = new Adder<String>();
Console.Writeline(stringAdder.AddTwoThings("Test,"123"));
Adder<int> intAdder = new Adder<int>();
Console.Writeline(intAdder.AddTwoThings(2,2));
For a much more detailed explanation of generics, I can't recommend enough the book CLR via C#.
It's generics - it's a form of type parameterisation. In your example, it's making l refer to a list of strings - the list will only ever contain strings: the compiler treats it (pretty much) as if everywhere that the API docs mention "T" it actually says "string". So, you can only add strings to it, and if you use the indexer you don't need to cast to string, etc.
To be honest, giving generics detailed coverage on an online forum is pretty much impossible. (In C# in Depth, I take nearly 50 pages talking about generics.) However, armed with the name of the feature, you should be in a much better position to find out more. The MSDN "Introduction to C# Generics" is probably a good starting point.
Asking specific questions about generics on SO is likely to yield good results - I just don't think it can really be covered properly in one question/answer.
This is .NET Generics. The type within the < > denotes the type of element contained in the list.
with ArrayList you'd have to cast the elements inside...
int x = (int)myArrayList[4];
with List you can avoid that step because the compiler already knows the type.
int x = myList[4];
Generics are available in .NET 2.0 and later.
Those are generics. You are making a List that only contains strings. You could also say
List<int>
and get a list that only contains ints.
Generics is a huge topic, too big for a single answer here.
Those are known as Generics (specifically List is a generic class).
Reading from MSDN
Generics (C# Programming Guide)
An Introduction to C# Generics
Generics in the .NET Framework
This is generics in action. A regular List stores items of type Object. This requires casting between types. This also will allow you to store any kind of item in one instance of a list. When you are iterating through items in that list you cannot be sure that they are all of a certain type (at least not without casting each item). For instance lets say you create a list like this:
List listOfStrings = new List();
Nothing prevents someone from doing something like this:
listOfStrings.add(6); //Not a string
A generic list would allow you to specify a strongly-typed list.
List<string> listOfStrings = new List<string>();
listOfStrings.add("my name"); //OK
listofStrings.add(6); //Throws a compiler error
There is a more thorough examples on here Generics
< > is for generics. In your specific example, it means that the List is a List of strings, not say a list of ints.
Generics are used to allow a type to be, well, generic. It's used ALOT in Collections to allow them to take different types so that they can function much like a normal array and still catch invalid types being assigned at compile time. Basically it allows a class to say "I need to be associated with some specific type T, but I don't want to hard code exactly what that type is, and let the user select it.". A simple array for instance might look something like:
public class MyArray<T> {
private T[] _list;
public MyArray() : this.MyArray(10);
public MyArray(int capacity)
{ _list = new T[capacity]; }
T this[int index] {
get { return _list[index]; }
set { _list[index] = value; }
}
}
Here, we have a private list of type T that is accessed by using our class like a normal array. We don't care what type it is, it doesn't matter to our code. But anyone using the class could use it as, say MyArray<string> to create a list of strings, while someone else might use it as MyArray<bool> and create a list of flags.

Categories

Resources