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

Переопределение абстрактного свойства с производным типом возвращаемого значения в С#

У меня есть четыре класса. Request, DerivedRequest, Обработчик, DerivedHandler. Класс Handler имеет свойство со следующим объявлением:

public abstract Request request { get; set; }

DerivedHandler должен переопределить это свойство, чтобы вместо него вместо DerivedRequest:

public override DerivedRequest request { get; set; }

Есть ли у кого-нибудь идеи о том, как сделать эту работу?

4b9b3361

Ответ 1

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

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

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

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

public class Handler: HandlerBase<Request>()

public class DerivedHandler: HandlerBase<DerivedRequest>()

Ответ 2

На языке С# вы не можете изменить подпись унаследованного метода, если вы не замените его другим методом с тем же именем. Этот метод называется "сокрытием элемента" или "затенением".

Если вы используете .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>
{
}

Ответ 3

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

public new DerivedRequest Request { get;set;}

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

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

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

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

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

Ответ 4

Изменить: Вы не можете изменить тип производного типа, но 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.
}

Ответ 5

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

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

Ответ 6

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; }
}