2013-11-22 4 views
5

Это то, что я столкнулся при использовании коллекции C# IListназначения объекта в C#

IList<MyClass> foo = new List<MyClass>(); 
var bar = new List<MyClass>(); 

foo.AddRange() // doesn't compile 
bar.AddRange() // compile 

Насколько я знаю, в C# (наоборот от C++), когда мы создаем объект с этим синтаксисом тип объекта получает правую сторону (присвоение), а не левую (декларация).

Пропустить что-то здесь!

EDIT

Я до сих пор не понимаю, даже после того, как ваши ответы, Foo и бар имеют одинаковый тип! enter image description here

+2

«var» относится к списку типов , который имеет метод «AddRange», тогда как foo имеет тип IList , который является интерфейсом, который не имеет метода «AddRange». – sjkm

+0

Но оба они получают экземпляр типа List

+0

@Schneider Это верно, но с точки зрения компилятора 'foo' имеет тип' IList <> 'not' List <> ' – rhughes

ответ

18

Там нет ничего настолько тонки, что происходит здесь:

  • Foo имеет тип IList<MyClass> и IList<T> не имеет метод AddRange
  • бар имеет тип List<MyClass> и List<T> действительно есть метод AddRange.

Это все. Это было бы точно так же в C++.

Обновление: в редактируемом дополнении вы вызываете GetType(), который получает тип времени выполнения объекта - во время компиляции он ищет статический тип переменных foo и bar.

Думая о Object myObj = "MyString" может прояснить ситуацию, потому что есть более очевидная разница между «Object» и «строкой», несмотря на то, что они имеют такое же отношение наследования как IList и список

+0

Посмотреть мои правки ... –

8

Проблема заключается в том, что вы используете интерфейс и IList не AddRange но List имеет AddRange

Если вы измените его на

List<MyClass> foo = new List<MyClass>(); 

он будет работать. поскольку он имеет этот метод.

Вот что IList имеет

Вы также можете сделать

IEnumerable<MyClass> foo = new List<MyClass>(); 

И вы увидите, что это ограничивает его еще более

EDIT ДЛЯ EDIT:

они оба быть тем же самым типом, потому что все еще Lists. Разница связана с переменной, которую вы используете. Используя интерфейс, вы ограничиваете операции теми, которые поддерживает интерфейс. Так как List реализует IList, IList имеет подмножество операций, которое имеет List.

Подлежащим объектом является объект List.

+0

Посмотреть мои правки ... –

+0

@Schneider Посмотреть обновленный ответ –

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 
2

Основным типом foo является List, но его статический тип, используемый компилятором для обеспечения правильности, равен IList<T>. Все, что вы вызываете на foo, должно быть объявлено как часть типа IList<T>.

0

Я не понял ваш вопрос, но в этой ситуации C# и C++ действуют одинаково. В вашем примере, чтобы обеспечить, что код будет скомпилирован вы могли бы написать

IList<MyClass> foo = new List<MyClass>(); 
var bar = new List<MyClass>(); 

((List<MyClass>)foo).AddRange(); 
bar.AddRange() // compile 

На самом деле он имеет тот же смысл, что и dynamic_cast в C++.

0

Поскольку все сказанное IList не поддерживает AddRange, и его не нужно поддерживать.

Вы можете:

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. 

Я также думаю, интерфейс не будет поддерживать все функции на классе в какой-то момент вы должны абстракцию, и это должно быть основано на интерфейса принцип сегрегации.

Смежные вопросы