This is something I encountered while using the C# IList collections
IList<MyClass> foo = new List<MyClass>();
var bar = new List<MyClass>();
foo.AddRange() // doesn't compile
bar.AddRange() // compile
As far as I know, in C# (on the contrary of C++) when we create an object with this syntax, the object type get the right side (assignment) and not the left one (declaration).
Do I miss something here !
EDIT
I still don't get it, even after your answers, foo and bar have the same type !
There's nothing so subtle going on here:
foo has the type IList<MyClass> and IList<T> doesn't have an AddRange method
bar has the type List<MyClass> and List<T> does have an AddRange method.
That's all. It would be just the same in C++.
Update: In the edited-in addition, you're calling GetType(), which gets the run-time type of the object - at compile time the compiler is looking at the static type of the foo and bar variables.
Thinking about Object myObj = "MyString" might make things clearer, because there is a more obvious difference between an 'Object' and a 'String', even though they have the same inheritance relationship as IList and List
The problem is that you are using the interface and IList does not have AddRange but List does have AddRange
If you change it to
List<MyClass> foo = new List<MyClass>();
it will work. as it has this method.
Here is what IList has
You can also do
IEnumerable<MyClass> foo = new List<MyClass>();
And you will find that this constrains it even more
EDIT FOR YOUR EDIT:
They will both be the same type becuase both are still Lists. The difference comes in with the variable that you are using. By using the interface, you are limiting the operations to those that the interface supports. As List implements IList, IList has a subset of the operations that List has.
The underlying object is still a List.
The underlying type of foo is List, but its static type, which the compiler uses to ensure correctness, is IList<T>. Anything that you invoke on foo must be declared as part of the IList<T> type.
Try:
List<MyClass> foo = new List<MyClass>(); // CHANGED TO List<> rather than IList<>
var bar = new List<MyClass>();
foo.AddRange() // doesn't compile
bar.AddRange() // compile
Also the IList declares a behavior and not a concrete type. Please see here
http://msdn.microsoft.com/en-us/library/system.collections.ilist%28v=vs.110%29.aspx
In the a List you can add items and IList type is an already constructed type, which implements this interface.
I have not understood your question, but in this situation C# and C++ act the same way. In your example that to provide that the code would be compiled you could write
IList<MyClass> foo = new List<MyClass>();
var bar = new List<MyClass>();
( (List<MyClass> )foo ).AddRange();
bar.AddRange() // compile
In fact it has the same sense as dynamic_cast in C++.
As the all said IList does not support AddRange and it does not need to support it.
You can:
1 ) ((List<MyClass>)foo).AddRange(anotherList);
2 ) You can also use extension method to AddRange
3 ) There are another workarounds for this problem e.g. Concat etc.
I think also, the interface shall not support every function on the class at some point you need abstraction and this shall be based on interface segregation principle.
Related
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.
So lets say I have a class like
public class Complex { } // this is what I mean when I say List<Complex>
// its just a user-defined class or type if you will
Now let's say I have a method which returns a list that holds objects.
Now let's say I can further guarantee that each of these objects in the list is actually of type Complex (in other words List < Complex >)
I would like the most painless way of casting this list as possible. A one-liner would be ideal, but a few lines would be fine too.
Here is what I tried (but doesn't work - InvalidCastOperation exception):
// Sorry this is so hard to read! Also .Cast<Complex>() doesn't work either :(
return (ComplexCollection) ((List<Complex>) ((List<object>) complexElementsDictionary["ComplexElementCollection"]).OfType<Complex>());
Some specifics about this code snippet:
ComplexCollection inherits List<Complex>
complexElementsDictionary is of type (Dictionary<string, List<object>)
So in plain terms I'm asking a Dictionary<> for its corresponding list of objects. Then I try to cast this list to what its supposed to be, which is a list of Complex.
Note - Please try to ignore the fact that I am casting like this at runtime. I'm deserializing an XML collection (in app.config actually) and this is how I've chosen to do it. There may be a better way, but for now I just want to see if anyone knows a way to do what I'm asking.
Thank you so much! I hope it is clear what I'm asking, and if not I'll update the question.
Breaking up your example code and modifying it slightly to use Cast():
List<object> list = complexElementsDictionary["ComplexElementCollection"];
List<Complex> typedList = list.Cast<Complex>().ToList();
You now have a list of objects of the required type. But what you actually want is an instance of your collection object, and this cannot be obtained by another cast. That is, you can't do this:
ComplexCollection collection = (ComplexCollection)typedList;
because typedList simply isn't an instance of ComplexCollection and there is no conversion operator available to the compiler to convert from List<Complex> to ComplexCollection.
You will need to create your instance and add the Complex objects to it:
ComplexCollection collection = new ComplexCollection();
foreach(Complex c in typedList){
collection.Add(c);
}
Or in just four lines:
ComplexCollection collection = new ComplexCollection();
foreach(Complex c in complexElementsDictionary["ComplexElementCollection"].Cast<>(Complex)){
collection.Add(c);
}
To convert a List<object> to List<Complex> is as simple as:
List<object> objectList = complexElementsDictionary["ComplexElementCollection"];
List<Complex> complexList = objectList.Cast<Complex>().ToList();
However you can't cast a List<Complex> to ComplexCollection just because ComplexCollection inherits from List<Complex>. (the other way around is fine though)
List<T> has a constructor which takes an IEnumerable<T> and adds the elements to a list. So I think what you need is to add this constructor to ComplexCollection:
public ComplexCollection(IEnumerable<Complex> values) : base(values)
{
/* plus any other logic you have */
}
And then your example with the return statement becomes:
return new ComplexCollection(
complexElementsDictionary["ComplexElementCollection"].Cast<Complex>()
);
To convert a list to a new type you can just do something as simple as
(ComplexCollection)(yourList.Select(x => (complexType)x).ToList());
That should work, basically your going through your list of objects in the dictionary and casting each item to the appropriate type, then converting that to a list and then converting your list to the more specific collection type.
I'm afried there's no direct solution. Maybe you could use ConvertAll:
// ol is of type List<Object>
List<Complex> cl = ol.ConvertAll(o=>(Complex)c);
I have a List of objects, which are of my type QuoteHeader and I want to pass this list as a list of objects to a method which is able to accept a List<object>.
My line of code reads...
Tools.MyMethod((List<object>)MyListOfQuoteHeaders);
But I get the following error at design time...
Cannot convert type 'System.Collections.Generic.List<MyNameSpace.QuoteHeader>'
to 'System.Collections.Generic.List<object>'
Do I need to do anything to my class to allow this? I thought that all classes inherit from object so I can't understand why this wouldn't work?
The reason this is not legal is because it is not safe. Suppose it were legal:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes; // this is not legal; suppose it were.
animals.Add(new Tiger()); // it is always legal to put a tiger in a list of animals
But "animals" is actually a list of giraffes; you can't put a tiger in a list of giraffes.
In C# this is, unfortunately, legal with arrays of reference type:
Giraffe[] giraffes = new Giraffe[10];
Animal[] animals = giraffes; // legal! But dangerous because...
animals[0] = new Tiger(); // ...this fails at runtime!
In C# 4 this is legal on IEnumerable but not IList:
List<Giraffe> giraffes = new List<Giraffe>();
IEnumerable<Animal> animals = giraffes; // Legal in C# 4
foreach(Animal animal in animals) { } // Every giraffe is an animal, so this is safe
It is safe because IEnumerable<T> does not expose any method that takes in a T.
To solve your problem you can:
Create a new list of objects out of the old list.
Make the method take an object[] rather than a List<object>, and use unsafe array covariance.
Make the method generic, so it takes a List<T>
Make the method take IEnumerable
Make the method take IEnumerable<object> and use C# 4.
You can't cast List<OneType> to List<OtherType> as it is actually the instances of the list you want to cast, as well as the List itself.
there is an extension method which will allow you to do this (MSDN reference):
IEnumerable<Object> myNewEnumerable = myEnumerable.Cast<Object>();
This method will attempt to cast each instance of the list of one type to the other type and add them to a new enumerable. it will throw an exception if any instance can't be cast.
As far as the system is concerned the two types for your lists are just different types, so it is like saying:
A objectOfTypeA;
B objectOfTypeB = (B) objectofTypeA;
To be able to do the cast there would have to be an implicit or explicit conversion between the types available, which there isn't (unless you provided one, which you might be able to do).
you expect it to work because List<object> will always be able to hold any type in another list, but when you think about it in those terms you can see why it doesn't.
I'm sure there is a more technically competent answer, but that is the gist of it I think.
you might be interested in reading Eric Lippert's series on Covariance and Contravariance as this may be helpful to you.
This question may also be useful
List<MyClass> x = someList.Select(f => (MyClass)f).ToList();
I'm presuming that you mean that the lists are of types which inherit from each other or can otherwise be cast from one type to another - in that case, try this:
Tools.MyMethod(MyListOfQuoteHeaders.Cast<OtherType>());
Thanks for the many responses.
I'll explain what I wanted to do and what I've come up with as a solution.
I needed a method that I could call by passing in a List of objects of any type and then output that list to XML. Also passed to the method would be a string which would be a system file structure path location which points to the location the XML file would be saved to. As I have an ever growing number of classes and types, I wanted to avoid writing multiple methods to cater for each type of class. I'm not sure if I've even gone about this the right way, but it's a lightweight solution to my problem and works. If there are any issues with it, or if anyone has any comments please feel free...
So... my method now looks like this...
public static Enums.Status WriteListToXML<T>(string outputPath, List<T> inboundList)
{
try
{
XmlSerializer xmlSerializer = new XmlSerializer(inboundList.GetType());
using (StreamWriter streamWriter = System.IO.File.CreateText(outputPath))
{
xmlSerializer.Serialize(streamWriter, inboundList);
}
return Enums.Status.Success;
}
catch (Exception ex)
{
return Enums.Status.Failure;
}
}
... and my calling line reads...
WriteListToXML<QuoteHeader>(#"C:\XMLDocuments\output\QuoteHeaders.xml", quoteHeadersList);
Like I said, it may not be the tidiest solution, but it works well in my scenario.
The problem is that at Compile time, the compiler emits 2 separate classes, 1 that represents List<MyClass> and one that represents List<Object>. They are essentially 2 separate types. That's how Generic types work, in .Net at least.
Assuming this is .Net, you could do
MyListOfQuoteHeaders.Cast<Object>()
which basically does
var objects = new List<Object>();
foreach(var item in MyListOfQuoteHeaders)
{
objects.Add((object)item);
}
return objects;
While I can upcast a string to an object, I cannot upcast an IList of strings to an IList of objects. How come? What to do now other that coping all items to a new IList?
static void ThisWorks()
{
IList<object> list = new List<object>();
list.Add("I can add a string since string : object");
}
static void ThisDoesNotWork()
{
// throws an invalid cast exception
IList<object> list = (IList<object>) new List<string>();
list.Add("I'm never getting here ... why?");
}
This is not possible as generics are invariant (as of C# 3.0).
You can workaround it with:
var objectList = list.Cast<object>().ToList();
Look at it like this: while a banana is a fruit, a basket of bananas is not a basket of fruit, since you can add oranges to the latter, but not the former. Your List<string> has stronger constraints than a List<object>.
Casting should always respect Liskow. For containers and iterators which do not admit modification, such casting is safe, but once things can be changed, you are skating close to the thin ice.
What you asked is essentially a question of Contravariance and Covariance. It is a concept in programming language design which talks about how methods and collections behave with respect to objects of two classes in the same inheritance hierarchy. Reading the Wikipedia article may help place your above curiosity in a larger, more general perspective.
string inherits from object but IList<string> does not inherit from IList<object> they are unrelated types and therefor you can't cast between them.
Just think what would happen if this worked:
// THIS CODE DOES NOT WORK
IList<object> list = new List<string>(); // this doesn't compile
list.Add(5); // because this is perfectly valid on IList<object> but not on IList<string>
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.