Подтвердить что ты не робот

Наследование по параметру с ограниченным общим типом

Я знаю, что невозможно наследовать от типового параметра типа, но это было бы удобно при реализации общего прокси для производных абстрактного типа: -)

Кто-нибудь знает, почему это невозможно?

Пример С#:

abstract class Foo
{
  public virtual void Bar()
  {
     // nop
  }
}

class FooProxy<TFoo> : TFoo
  where TFoo : Foo
{

  public override void Bar()
  {
    // do some stuff before
    base.Bar();
    // do some stuff after
  }

}

EDIT: Еще один код, чтобы проиллюстрировать пример того, как это можно использовать. Рассмотрим следующие производные от Foo:

class FooX : Foo
{
  public string X { get; set; }
  public override void Bar()
  {
    Console.WriteLine("Doing Bar X");
  }
}

class FooY : Foo
{
  public string Y { get; set; }
  public override void Bar()
  {
    Console.WriteLine("Doing Bar Y");
  }
}

И вызывающий код:

FooProxy<FooX> fooXProxy = new FooProxy<FooX>();
fooXProxy.X = "test X";
fooXProxy.Bar();

FooProxy<FooY> fooYProxy = new FooProxy<FooY>();
fooYProxy.Y = "test Y";
fooYProxy.Bar();

Код в переопределении FooProxy метода Bar() будет использоваться повторно при использовании FooX и FooY.

РЕДАКТИРОВАТЬ: Пересмотрено согласно Pete OHanlon answer: сделанный метод Bar() виртуальный.

4b9b3361

Ответ 1

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

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

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

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

Обновление:

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

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

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

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

Ответ 2

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

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

public virtual void Bar() {}

Ответ 3

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

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

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

Edit:

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

abstract class Foo<T>  
{  
    public virtual void Bar();  
}