用c#中的派生返回类型重写抽象属性



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

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

在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*/ }

这样,你在OOP方面就站在了明确的一边,你可以以明确的方式获得信息。

编辑:您不能更改派生类型的类型,但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; }
}

最新更新