Ускорение в .NET с использованием дженериков

Итак, у меня есть класс вроде этого:

public class A { 
  internal A(int i) { ... }
  public int Foo { get; set; }
}

Этот класс затем наследуется кучей сгенерированных классов, например:

public class B : A {
  ...
}

Конструктор, основанный на int, не подвергается наследуемому классу (по соображениям дизайна я не хочу, чтобы он был открыт). В моей библиотеке, которая содержит определение для класса A, у меня есть такой метод:

public T Load<T>() where T : A {
  //do some stuff, create an instance of T from an int, then return it
}

И тогда я буду использовать его следующим образом:

B b = Helper.Load<B>();

Поскольку конструктор, который я хочу использовать, не подвергается классу B, когда я делаю typeof(T).GetConstructor(typeof(int)) Я не возвращаю конструктор, поэтому хочу, чтобы я сделал это:

return (T)new A(/*some int */);

Но это дает мне ошибку времени выполнения System.InvalidCastException, что я не могу использовать тип A для типа B.

Как я могу достичь этого повышения?

Ответ 1

Вы можете просто использовать конструкторы по умолчанию, чтобы вы могли создавать объекты типа T с помощью ограничения new(). Тогда класс A может иметь виртуальный (или абстрактный по своему вкусу) метод, который принимает int как аргумент и инициализирует объект после запуска конструктора.

public class A {
    internal A() { }
    internal Initialize(int i) { Foo = i; }
    public int Foo { get; set; }
}

public class B : A { 
    internal B() { }
}

...

public T Load<T>() where T : A, new() {
    var ret = new T();
    ret.Initialize(i);
    return ret;
}

Если вы собираетесь использовать какой-то шаблон factory, вам не нужно смущаться инициализировать части объекта вне вызова конструктора, если это выполняется до того, как вы вернете объект в элемент управления вызывающего.

Ответ 2

Из того, что я понял, T происходит от A, поэтому вы не можете использовать A to T.

Ответ 3

В вашем примере вы не можете преобразовать A в B, потому что:

return (T)new A(/*some int */);

Создает экземпляр A, который не a B. Просто потому, что "B является A" не означает, что "A - это B". Вам нужно сначала создать экземпляр B, отдать его A, сделать то, что вы хотите, а затем увеличить его до B.

Я не уверен, что это будет скомпилировано, но вы можете попробовать следующее:

T blah = new T(5); //this means your B will need to implement a int constructor
A blah2 = (A)blah;
//operate on A specific operations in blah2
T upcasted = (T)blah2;
//alternatively
T upcasted = blah2 as T;

Рассмотрим рефакторинг вашего конструктора таким образом, чтобы вы инициализировали целое число как свойство, а не параметр конструктора. Я стараюсь иметь конструкторы по умолчанию (без параметров), чтобы общий код мог легко создавать класс.

Ответ 4

Вы не можете сделать это, измените свой дизайн.