Переоценить абстрактное свойство с выводом типа возврата в C#

StackOverflow https://stackoverflow.com/questions/6351025

Вопрос

У меня четыре класса. Запрос, Дериведрекест, Хэндлер, Деривальдлер. У класса обработчиков есть собственность со следующим объявлением:

public abstract Request request { get; set; }

DrevivedHandler должен переопределить это свойство, чтобы вместо этого возвращать DreivedRequest:

public override DerivedRequest request { get; set; }

У кого -нибудь есть идеи о том, как заставить эту работу?

Это было полезно?

Решение

Это не хороший способ структурировать вещи. Выполните одно из следующих

1) Просто не изменяйте тип возврата и обычно переопределяйте его в подклассе. В DerivedHandler Вы можете вернуть экземпляр DerivedRequest Используя подпись базового класса Request. Анкет Любой клиент -код, использующий этот, может выбрать его на DerivedRequest Если они хотят.

2) Вместо этого используйте дженерики, если они не должны быть полиморфными.

public abstract class HandlerBase<T> where T: Request
{
    public abstract T Request {get;set;}
}

public class Handler: HandlerBase<Request>()

public class DerivedHandler: HandlerBase<DerivedRequest>()

Другие советы

На языке C# вы Не разрешено изменять подпись унаследованного метода, если вы не замените его другим методом с тем же именем. Анкет Этот метод называется «скрывающимся членом» или «запетением».

Если вы используете .NET 2.0 или более позднее Request свойство в общий параметр Handler учебный класс. А DerivedHandler Класс затем указал DerivedRequest Класс как аргумент для этого параметра типа.

Вот пример:

// Handler.cs
public class Handler<TRequest> where TRequest : Request
{
    public TRequest Request { get; set; }
}

// DerivedHandler.cs
public class DerivedHandler : Handler<DerivedRequest>
{
}

За исключением скрытия оригинальной собственности:

public new DerivedRequest Request { get;set;}

Однако я настоятельно советую против этого. Скрытие чего -то, предполагаемого переопределением - это приглашает неприятности, особенно если свойство не является простой автоматической сгенерированной. Кроме того, если он использует его в качестве интерфейса или базового класса, исходная реализация (в этом случае, один класс выше в дереве наследования). Если вы реализуете абстрактный класс или интерфейс, вы даже не сможете скрыть исходную подпись, поскольку вам необходимо ее реализовать.

Обычно, если вы думаете об использовании new Ключевое слово, вы не на том пути. Есть случаи, когда это необходимо и необходимо, однако, в большинстве случаев это не так.

Вместо этого сделайте другое свойство:

public DerivedRequest DerivedRequest {/* make adequate conversions here*/ }

Таким образом, вы находитесь на ясной стороне, касающейся ООП, и вы получаете свою информацию ясным образом.

РЕДАКТИРОВАТЬ: Вы не можете изменить тип на производном типе, но new может помочь:

В производном типе ...

public new DerivedRequest request
{
   get{return (DerivedRequest) base.request;}
   set{base.request = value;}
}
public override Request request
{
   get{return base.request;}
   set{base.request = (DerivedRequest) value;} // Throws InvalidCastException if misused.
}

Это не возможно. Переопределение должно быть ковариатом для типа возврата (то есть тип возврата должен быть более конкретным или таким же) и противоречить параметрам (то есть тип параметра должен быть менее конкретным или таким же). Таким образом, ваш новый тип должен быть эффективно в то же время ковариант и противоположный по отношению к Request - это означает, что единственный возможный тип просто Request.

По этой причине в C# не разрешено изменять тип свойств для переопределения.

public class Request{}

public class DerivedRequest : Request{}

public class Handler<T>
  where T : Request
{
  public abstract T Request { get; set; }
}

public class DerivedHandler : Handler<DerivedRequest>
{
  public override DerivedRequest Request { get; set; }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top