简体   繁体   English

用 c# 中的派生返回类型覆盖抽象属性

[英]Overriding an abstract property with a derived return type in c#

I have four classes.我有四节课。 Request, DerivedRequest, Handler, DerivedHandler.请求、派生请求、处理程序、派生处理程序。 The Handler class has a property with the following declaration:处理程序 class 具有具有以下声明的属性:

public abstract Request request { get; set; }

The DerivedHandler needs to override this property so that it returns DerivedRequest instead: DerivedHandler 需要覆盖此属性,以便它返回 DerivedRequest:

public override DerivedRequest request { get; set; }

Does anyone have any ideas about how to make this work?有人对如何使这项工作有任何想法吗?

This isn't really a good way to structure things.这并不是一个很好的结构化事物的方法。 Do one of the following执行以下操作之一

1) Just don't change the return type, and override it normally in the subclass. 1)只是不要更改返回类型,并在子类中正常覆盖它。 In DerivedHandler you can return an instance of DerivedRequest using the base class signature of Request .DerivedHandler ,您可以使用Request的基本 class 签名返回DerivedRequest的实例。 Any client code using this can choose to cast it to DerivedRequest if they want to.如果需要,任何使用它的客户端代码都可以选择将其转换为DerivedRequest

2) Use generics instead if they are not supposed to be polymorphic. 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>()

In the C# language you are not allowed to change the signature of an inherited method, unless you substitute it with another method with the same name .在 C# 语言中,您不得更改继承方法的签名,除非您将其替换为具有相同名称的其他方法 This technique is referred to as "member hiding" or "shadowing".这种技术被称为“成员隐藏”或“隐藏”。

If you are using .NET 2.0 or later, you could solve this problem by turning the return type of the Request property into a generic type parameter of the Handler class.如果您使用的是 .NET 2.0 或更高版本,则可以通过将Request属性的返回类型转换为Handler class 的泛型类型参数来解决此问题。 The DerivedHandler class would then specify the DerivedRequest class as argument for that type parameter.然后, DerivedHandler class 将指定DerivedRequest class 作为该类型参数的参数。

Here's an example:这是一个例子:

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

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

Except for hiding the original property:除了隐藏原始属性:

public new DerivedRequest Request { get;set;}

However, I strongly advise against that.但是,我强烈建议不要这样做。 Hiding something supposed to be overriden is inviting trouble, especially if the property isn't a simple auto generated one.隐藏应该被覆盖的东西会招来麻烦,特别是如果该属性不是简单的自动生成的。 Also, if using it as an interface or base class, the original implementation (in that case, one class higher in the inheritance tree).此外,如果将其用作接口或基础 class,则为原始实现(在这种情况下,inheritance 树中的 class 更高)。 If you are implementing an abstract class or interface, you won't even be able to hide the original signature, as you are required to implement it.如果您正在实现抽象 class 或接口,您甚至无法隐藏原始签名,因为您需要实现它。

Usually, if you think about using the new keyword, you are on the wrong track.通常,如果您考虑使用new关键字,那么您就走错了路。 There are cases where it is necessary and required, however, in most cases, it isn't.在某些情况下,它是必要的和必需的,但是,在大多数情况下,它不是。

Instead, make another property:相反,创建另一个属性:

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

That way, you are on the clear side concerning OOP and you get your information in a clear way.这样,您就可以清楚地了解 OOP 并以清晰的方式获取信息。

Edit: You can't change the type on a derived type, but new might help:编辑:您不能更改派生类型的类型,但new可能会有所帮助:

In the derived type...在派生类型中...

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

This is not theoretically possible.这在理论上是不可能的。 The override must be covariant for return type (that is, the return type must be more specific or the same), and contravariant for parameter (that is, parameter type must be less specific or the same).覆盖对于返回类型必须是协变的(即返回类型必须更具体或相同),而对于参数必须是逆变的(即参数类型必须不太具体或相同)。 So your new type must be effectively at the same time covariant and contravariant with respect to the Request -- that means, the only possible type is just Request .因此,您的新类型必须同时有效地与Request协变和逆变——这意味着,唯一可能的类型就是Request

For this reason, it's not allowed in C# to change the type of properties for overrides.因此,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 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM