Использование общего параметра в качестве базового класса [duplicate]

Если вы посмотрите на исходный код для итератора ArrayList (частный вложенный класс Itr), вы увидите недостаток в коде.

Код должен быть с ошибкой, быстрый, который делается внутри итератора внутри, вызывая checkForComodification(), однако hasNext() не делает этот вызов, вероятно, по соображениям производительности.

Вместо hasNext():

public boolean hasNext() {
    return cursor != size;
}

Это означает, что когда вы находитесь в элементе second last в списке, а затем удалите элемент (любой элемент), размер уменьшается, а hasNext() думает, что вы 're на последнем элементе (которого вы не были) и возвращает false, пропуская итерацию последнего элемента без ошибок.

OOPS !!!!

26
задан VirtualStaticVoid 14 September 2009 в 11:07
поделиться

3 ответа

Потому что вы не можете. Дженерики - это не шаблоны. Вы не должны думать о них, как шаблоны C ++, и ожидать такого же поведения.

Спецификация C # явно запрещает использование параметров типа в качестве базового класса:

C # 3.0 Спецификация языка: параметры типа (§4.5)

Параметр типа не может использоваться напрямую для объявления базового класса (§10.2.4) или интерфейса (§13.1.3).

Обновление:

Я понимаю, что вы хотите сделать и его использование. Это традиционный пример использования шаблонов C ++. В частности, если это было возможно сделать с использованием генераторов C #, такие вещи, как Moq library , могли бы быть полезны. Проблема в том, что C ++-шаблоны - это время компиляции «find and replace», в то время как C # generics - это время выполнения.

Чтобы продемонстрировать этот факт, для этого класса:

class Test<T> where T : class {
    // whatever contents it might have...
} 

только один ИЛ будет выпущен во время компиляции и во время выполнения, компилятор JIT будет генерировать единый собственный код для всех типов типа ссылочного типа. Это совсем не похоже на C ++-шаблоны, где собственный код будет испускаться для каждого T отдельно (он подвержен оптимизации, но концептуально, они являются полностью отдельными фрагментами кода).

45
ответ дан Mehrdad Afshari 19 August 2018 в 16:08
поделиться
  • 1
    Я хочу upvote, но я думаю, что ваши деньги, C ++ шаблоны не являются C # generics ... – Spence 14 September 2009 в 11:04
  • 2
    Другими словами, невозможно, чтобы объект соответствовал как двоичному макету производного универсального класса (который требует, чтобы базовый подобъект был фиксированным, согласованным размером) и бинарным макетом базового класса. База "фиксированного размера" требование налагается CLR и не является основополагающим - можно хранить смещения для каждого из подобъектов, и это то, что также необходимо для языков, поддерживающих множественное виртуальное наследование, но .NET решил избежать этого дополнительного осложнения. – Ben Voigt 11 September 2013 в 16:16

Вы не можете наследовать от параметра generic type, потому что этот тип неизвестен во время компиляции, поэтому компилятор не может понять, что такое суперкласс. Я понимаю, что на первый взгляд тот факт, что компилятор может определить, что & lt; T & gt; похоже, предполагает, что он должен иметь возможность выяснить, что такое T, но две вещи разные.

Кроме того, у вас есть логическая проблема в баре. Вы не можете вызвать base.Bar, потому что это абстрактный тип. Чтобы исправить это, вам нужно будет изменить свою реализацию в Foo на

public virtual void Bar() {}
6
ответ дан Pete OHanlon 19 August 2018 в 16:08
поделиться

Поскольку Foo является абстрактным типом.

Если вы внедрили Foo в класс, то использовали его в шаблоне, тогда вы могли бы это сделать.

Вы также можете использовать интерфейс для сделайте то, что вы пытаетесь сделать, я верю.

Edit:

Во второй раз, глядя на ваш код, это бессмысленно. Вам нужно будет создать базовый класс типа GENERIC, а затем извлечь из этого, чтобы достичь того, что вы пытаетесь сделать. Это также придало бы еще больший смысл ...

abstract class Foo<T>  
{  
    public virtual void Bar();  
}
1
ответ дан Spence 19 August 2018 в 16:08
поделиться