在 C# 中使用派生返回类型覆盖抽象属性

发布于 2024-11-15 05:35:38 字数 283 浏览 4 评论 0原文

我有四节课。请求、派生请求、处理程序、派生处理程序。 Handler 类有一个带有以下声明的属性:

public abstract Request request { get; set; }

DerivedHandler 需要重写此属性,以便它返回 DerivedRequest:

public override DerivedRequest request { get; set; }

有人知道如何实现此功能吗?

I have four classes. Request, DerivedRequest, Handler, DerivedHandler. The Handler class has a property with the following declaration:

public abstract Request request { get; set; }

The DerivedHandler needs to override this property so that it returns DerivedRequest instead:

public override DerivedRequest request { get; set; }

Does anyone have any ideas about how to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

尘世孤行 2024-11-22 05:35:38

这实际上并不是一个构建事物的好方法。执行以下操作之一

1) 只是不要更改返回类型,并在子类中正常覆盖它。在 DerivedHandler 中,您可以使用 Request 的基类签名返回 DerivedRequest 的实例。如果愿意,任何使用此方法的客户端代码都可以选择将其转换为 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>()

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. In DerivedHandler you can return an instance of DerivedRequest using the base class signature of Request. Any client code using this can choose to cast it to DerivedRequest if they want to.

2) Use generics instead if they are not supposed to be polymorphic.

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

public class Handler: HandlerBase<Request>()

public class DerivedHandler: HandlerBase<DerivedRequest>()
风尘浪孓 2024-11-22 05:35:38

在 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>
{
}

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. 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. The DerivedHandler class would then specify the DerivedRequest class as argument for that type parameter.

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>
{
}
情何以堪。 2024-11-22 05:35:38

除了隐藏原始财产之外:

public new DerivedRequest Request { get;set;}

但是,我强烈建议不要这样做。隐藏一些应该被覆盖的东西会带来麻烦,特别是如果该属性不是简单的自动生成的属性。另外,如果将其用作接口或基类,则为原始实现(在这种情况下,为继承树中较高的一个类)。如果您正在实现抽象类或接口,您甚至无法隐藏原始签名,因为您需要实现它。

通常,如果您考虑使用 new 关键字,那么您就走错了路。在某些情况下,这是必要和必需的,但在大多数情况下,并非如此。

相反,创建另一个属性:

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

这样,您就可以清楚地了解 OOP,并以清晰的方式获取信息。

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

Usually, if you think about using the new keyword, you are on the wrong track. 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.

无法回应 2024-11-22 05:35:38

编辑:
您无法更改派生类型的类型,但 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.
}

Edit:
You can't change the type on a derived type, but new might help:

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.
}
萌︼了一个春 2024-11-22 05:35:38

这在理论上是不可能的。覆盖对于返回类型必须是协变的(即,返回类型必须更具体或相同),对于参数来说必须是逆变的(即参数类型必须是不太具体或相同)。因此,您的新类型必须同时有效地针对 Request 进行协变和逆变——这意味着,唯一可能的类型就是 Request

因此,C# 中不允许更改重写的属性类型。

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.

For this reason, it's not allowed in C# to change the type of properties for overrides.

裸钻 2024-11-22 05:35:38
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; }
}
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; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文