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

Как вернуть подтип в переопределенном методе подкласса в С#?

У меня есть подкласс с переопределенным методом, который, как я знаю, всегда возвращает определенный подтип типа возврата, объявленного в базовом классе. Если я напишу код таким образом, он не будет компилироваться. Поскольку это, вероятно, не имеет смысла, позвольте мне привести пример кода:

class BaseReturnType { }
class DerivedReturnType : BaseReturnType { }

abstract class BaseClass {
    public abstract BaseReturnType PolymorphicMethod();
}

class DerivedClass : BaseClass {
    // Compile Error: return type must be 'BaseReturnType' to match 
    // overridden member 'BaseClass.PolymorphicMethod()'
    public override DerivedReturnType PolymorphicMethod() { 
        return new DerivedReturnType(); 
    }
}

Есть ли способ сделать это на С#? Если нет, то какой лучший способ добиться чего-то подобного? И почему это не разрешено? Похоже, что это не допускает какой-либо логической несогласованности, поскольку любой объект, возвращаемый с помощью переопределенного метода, еще is BaseReturnType. Возможно, я кое-что не рассмотрел. Или, может быть, причина технологическая или историческая.

4b9b3361

Ответ 1

К сожалению нет, ковариантные типы возврата не поддерживаются в С# для переопределения метода. (Точно контравариантные типы параметров.)

Если вы реализуете интерфейс, вы можете реализовать его явно со "слабой" версией, а также предоставить публичную версию с более сильным контрактом. Для простого переопределения родительского класса у вас нет такой роскоши, я боюсь:(

(EDIT: у Marc есть разумное решение - хотя это довольно уродливо, а метод скрытия - это, как правило, плохой читабельность. Без обид означало Marc;)

Я считаю, что это на самом деле ограничение CLR, а не только языковое, но я вполне мог ошибаться.

(В истории история Java (язык) имела такое же ограничение до 1,5 - но она приобрела ковариацию одновременно с генериками.)

Ответ 2

Вы можете сделать класс общим, если это вас не беспокоит:

    class BaseReturnType { }
    class DerivedReturnType : BaseReturnType { }

    abstract class BaseClass<T> where T : BaseReturnType
    {
        public abstract T PolymorphicMethod();
    }

    class DerivedClass : BaseClass<DerivedReturnType>
    {
        // Error: return type must be 'BaseReturnType' to match 
        // overridden member 'BaseClass.PolymorphicMethod()'
        public override DerivedReturnType PolymorphicMethod()
        {
            return new DerivedReturnType();
        }
    }

Ответ 3

Вы можете сделать это, если вы добавите дополнительный метод для переопределения (поскольку вы не можете override и new метод с тем же именем в том же типе):

abstract class BaseClass
{
    public BaseReturnType PolymorphicMethod()
    { return PolymorphicMethodCore();}

    protected abstract BaseReturnType PolymorphicMethodCore();
}

class DerivedClass : BaseClass
{
    protected override BaseReturnType PolymorphicMethodCore()
    { return PolymorphicMethod(); }

    public new DerivedReturnType PolymorphicMethod()
    { return new DerivedReturnType(); }
}

Теперь у вас есть метод PolymorphicMethod на каждом уровне с правильным типом.

Ответ 4

Дженерики не обязательно подходят. В частности, тип (из Derived) не считается типом (из Base).

Сначала добавьте новый метод в ваш производный класс, который вернет значение с правильным типом. Во-вторых, отметьте переопределяющий метод недопустимым и передайте его новому методу.

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

Извиняюсь, если код не совсем прав; Я привык к VB.net.

abstract class C1 {
    public abstract IEnumerable<Byte> F1();
}
class C2 : C1 {
    public sealed override IEnumerable<Byte> F1() {
        Return F2();
    }
    public overridable IList<Byte> F2() {
        Return {1, 2, 3, 4};
    }
}

Ответ 5

class BaseReturnType { }
class DerivedReturnType : BaseReturnType { }

abstract class BaseClass {
    public abstract BaseReturnType PolymorphicMethod();
}

class DerivedClass : BaseClass {
    // Error: return type must be 'BaseReturnType' to match 
    // overridden member 'BaseClass.PolymorphicMethod()'
    public override BaseReturnType PolymorphicMethod() { 
        return new DerivedReturnType(); 
    }
}

это должно работать

Ответ 6

Измените подпись метода на классе Derived на:

 public override BaseReturnType PolymorphicMethod() 
 {
    return new DerivedReturnType();     
 }

С# не поддерживает варианты возвращаемых типов. Вы можете проверить этот пост, чтобы сделать это с помощью Generics... http://srtsolutions.com/blogs/billwagner/archive/2005/06/17/covaraint-return-types-in-c.aspx

Здесь пример с использованием Generics в вашей модели:

public class BaseReturnType
{
}
public class DerivedReturnType : BaseReturnType
{
}

public abstract class BaseClass<T> where T : BaseReturnType
{
    public abstract T PolymorphicMethod();

}

public class DerviedClass : BaseClass<DerivedReturnType>
{
    public override DerivedReturnType PolymorphicMethod()
    {
        throw new NotImplementedException();
    }
}

Ответ 7

Мне кажется, что вам нужно вернуть интерфейс, а не базовый класс.