在c中覆盖具有派生返回类型的抽象属性
我有四个类。 Request,DerivedRequest,Handler,DerivedHandler。处理程序类具有以下声明的属性:在c中覆盖具有派生返回类型的抽象属性
public abstract Request request { get; set; }
的DerivedHandler需要,以便它返回DerivedRequest而不是覆盖此属性:
public override DerivedRequest request { get; set; }
有没有人有关于如何使这项工作任何想法?
这不是真正构建的东西的好方法。执行以下操作之一:
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>()
如果存在多种情况,例如我想以使用派生类的方式重写的多个属性,那么我需要执行类似于以下操作的类:class HandlerBase 其中A:classA,B:classB,...' ? – Javidan 2017-02-06 12:15:49
编辑: 您不能更改类型上派生类型,但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.
}
这通常不被称为“覆盖” – Vlad 2011-06-14 22:45:55
除了隐藏原物业:
public new DerivedRequest Request { get;set;}
但是,我强烈建议不要这样做。隐藏应该被覆盖的东西会引起麻烦,特别是如果该属性不是简单的自动生成的属性。另外,如果使用它作为接口或基类,原始实现(在这种情况下,继承树中的一个类更高)。如果你正在实现一个抽象类或接口,你甚至不能隐藏原始签名,因为你需要实现它。
通常情况下,如果您考虑使用new
关键字,则说明您的方法错误。在有些情况下,它是必要和必需的,然而,在大多数情况下,事实并非如此。
相反,使他人财产:
public DerivedRequest DerivedRequest {/* make adequate conversions here*/ }
这样的话,你是关于面向对象的明确侧,你会得到一个明确的方式您的信息。
在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>
{
}
你当然可以这样做;只要Liskov替代原则得以维持,“OOP”中的任何内容都不得阻止你这样做。例如,在面向对象语言“C++”中,重写一个返回一个返回Tiger的Animal的方法是合法的。这个特性被称为“返回类型协方差”,它在OOP语言中相当普遍。但它不是C#的一个特性。 – 2011-06-15 03:51:58
@Eric Lippert你是对的。我熟悉_return类型协变_和_parameter类型contravariance_。自1.0以来,C#为代表类型提供了支持。后来C#4.0增加了对通用接口和委托类型的支持。谢谢你指出我的错误,我纠正了答案。 – 2011-06-15 09:10:32
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; }
}
这不是严格把好OOP,因为它违反了接口。某些类型的setter操作(带有非常值的'')会意外抛出。 – recursive 2011-06-14 22:46:11
在这种情况下,我想,我不需要一个setter。我可以创建一个私有属性并将其设置在构造函数中。这会照顾setter操作例外,是吗? – Trevor 2011-06-14 22:59:04
在这种情况下,您不需要重写该属性。只要构造函数只接受DerivedRequest。 – recursive 2011-06-15 02:28:22