Создание общего экземпляра класса из статического метода в производном классе - PullRequest
7 голосов
/ 27 мая 2010

У меня есть класс в C # с шаблоном и статическим методом, похожим на

class BClass<T>
{
  public static BClass<T> Create()
  {
    return new BClass<T>();
  }
 }

Из этого я извлекаю класс и указываю параметр шаблона для базового класса

class DClass : BClass<int> { }

Проблема возникает, когда я пытаюсь использовать статический метод для создания экземпляра D

class Program
{
  static void Main(string[] args)
  {
    DClass d = DClass.Create();
  }
}

Дает ошибку компилятора «Не удается неявно преобразовать тип« Test.BClass »в« Test.DClass ».»

Добавление приведенных ниже приведений приводит к исключению во время выполнения.

DClass d = (DClass)DClass.Create();

Есть ли какой-нибудь лаконичный способ, позволяющий статическому методу создавать экземпляры производного класса? В идеале я хотел бы получить эквивалент определения типа c ++, и мне не нужен следующий синтаксис (который работает).

BClass<int> d = DClass.Create();

Ответы [ 3 ]

7 голосов
/ 27 мая 2010

Похоже, что вы хотите, чтобы DClass был псевдонимом для BClass<int>. Но это не то, что у вас здесь. То, что у вас есть, это то, что DClass происходит от BClass<int>. Таким образом, при вызове DClass.Create(); создается BClass<int>, который не a DClass (это наоборот).

Это может прояснить ситуацию. Предположим, у вас была эта иерархия:

class Rectangle {
    static Rectangle Create() {
        return new Rectangle();
    }
}

class Square : Rectangle { }

// code elsewhere
var shape = Square.Create(); // you might want this to return a square,
                             // but it's just going to return a rectangle

Один из способов получить что-то похожее на желаемую функциональность может состоять в определении вашего Create метода следующим образом:

static TClass Create<TClass>() where TClass : BClass<T>, new() {
    return new TClass();
}

// code elsewhere
var shape = DClass.Create<DClass>();

Это немного грязно, хотя (и также требует, чтобы вы написали конструктор без параметров для DClass). Если вы не можете использовать метод Create для создания экземпляров ваших объектов, подумайте о написании фабричного класса для него.

6 голосов
/ 27 мая 2010

Да, это возможно при наличии ссылки на тип самого типа. Обратите внимание, что в мире .NET мы говорим о дженериках, а не о шаблонах, которые имеют важные различия в том, как они работают.

class BClass<T, TSelf> where TSelf: BClass<T, TSelf>, new() {
    public static TSelf Create() {
        return new TSelf();
    }
}

class DClass: BClass<int, DClass> {}

class Program {
    static void Main(string[] args) {
        DClass d = DClass.Create();
    }
}
1 голос
/ 27 мая 2010
class BClass<T>
    {
        public static T1 Create<T1, T2>() where T1 : BClass<T2>, new()
        {
            return new T1();
        }
    }

    class DClass : BClass<int> { }

    class Program
    {
        static void Main(string[] args)
        {
            DClass d = DClass.Create<DClass, int>();
        }
    }
...