5

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 ! enter image description here

5
  • 2
    "var" is of Type List<MyClass> which has the method "AddRange" whereas foo is of type IList<T> which is an interface that doesn't have the "AddRange" method. Commented Nov 22, 2013 at 15:22
  • But both of them get instantiated with the type List<MyClass> Commented Nov 22, 2013 at 15:23
  • @Schneider That is true, but from the compiler's point of view, foo is of type IList<> not List<> Commented Nov 22, 2013 at 15:24
  • Yes but you cast one variable (foo) implicitly to IList<T> Commented Nov 22, 2013 at 15:24
  • The point is that the object you created is of type List, but the variable you use to refer to it isn't. Commented Nov 27, 2013 at 17:31

7 Answers 7

18

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

Sign up to request clarification or add additional context in comments.

Comments

8

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.

Comments

2

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.

Comments

0

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

Comments

0

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.

Comments

0

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++.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.