Ускорение в .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
Вы не можете сделать это, измените свой дизайн.