Указание типа возврата абстрактного метода из базового класса в соответствии с подклассом
У меня есть следующая структура:
abstract class Base {
public abstract List<...> Get(); //What should be the generic type?
}
class SubOne : Base {
public override List<SubOne> Get() {
}
}
class SubTwo : Base {
public override List<SubTwo> Get() {
}
}
Я хочу создать абстрактный метод, который возвращает любой класс, к которому относится конкретный подкласс. Итак, как видно из примера, метод в SubOne
должен вернуться List<SubOne>
тогда как метод в SubTwo
должен вернуться List<SubTwo>
,
Какой тип указывать в подписи, объявленной в базовом классе?
[ОБНОВИТЬ]
Спасибо за опубликованные ответы.
Решение состоит в том, чтобы сделать абстрактный класс универсальным, например:
abstract class Base<T> {
public abstract List<T> Get();
}
class SubOne : Base<SubOne> {
public override List<SubOne> Get() {
}
}
class SubTwo : Base<SubTwo> {
public override List<SubTwo> Get() {
}
}
5 ответов
Ваш абстрактный класс должен быть универсальным.
abstract class Base<T> {
public abstract List<T> Get();
}
class SubOne : Base<SubOne> {
public override List<SubOne> Get() {
}
}
class SubTwo : Base<SubTwo> {
public override List<SubTwo> Get() {
}
}
Если вам нужно сослаться на абстрактный класс без аргумента универсального типа, используйте интерфейс:
interface IBase {
//common functions
}
abstract class Base<T> : IBase {
public abstract List<T> Get();
}
public abstract class Base<T>
{
public abstract List<T> Get();
}
class SubOne : Base<SubOne>
{
public override List<SubOne> Get() { return new List<SubOne>(); }
}
class SubTwo : Base<SubTwo>
{
public override List<SubTwo> Get() { return new List<SubTwo>(); }
}
Попробуй это:
public abstract class Base<T> {
public abstract List<T> Foo();
}
public class Derived : Base<Derived> { // Any derived class will now return a List of
public List<Derived> Foo() { ... } // itself.
}
Я не думаю, что вы можете сделать его конкретным подклассом. Вы можете сделать это, хотя:
abstract class Base<SubClass> {
public abstract List<SubClass> Get();
}
class SubOne : Base<SubOne> {
public override List<SubOne> Get() {
throw new NotImplementedException();
}
}
class SubTwo : Base<SubTwo> {
public override List<SubTwo> Get() {
throw new NotImplementedException();
}
}
Если у вас есть ситуация, когда ваш базовый класс не может быть универсальным по разным причинам, этот метод может быть полезен:
abstract class Base {
}
interface IHasGetter<T> {
List<T> Get();
}
static class HasGetterHelper {
public static List<T> Get<T>(this T v) where T: IHasGetter<T> => v.Get();
}
class SubOne : Base, IHasGetter<SubOne> {
public List<SubOne> Get() {
throw new NotImplementedException();
}
}
class SubTwo : Base, IHasGetter<SubTwo> {
public List<SubTwo> Get() {
throw new NotImplementedException();
}
}
Если вы не можете добавить интерфейс к своим подклассам и по-прежнему не можете добавить универсальные шаблоны к базовому типу, этот метод может быть полезен: (К сожалению, вы не можете сделать GetImpl защищенным, поскольку вспомогательному классу не разрешено находиться внутри базового класса )
abstract class Base {
public abstract List<T> GetImpl<T>() where T:Base;
}
static class HasGetterHelper {
public static List<T> Get<T>(this T v) where T: Base => v.GetImpl<T>();
}
class SubOne : Base {
public override List<T> GetImpl<T>() {
throw new NotImplementedException();
}
}
class SubTwo : Base {
public override List<T> GetImpl<T>() {
throw new NotImplementedException();
}
}
В обоих случаях это будет работать должным образом:
class Tester
{
List<SubOne> TestIt() => new SubOne().Get();
}