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

时间:2011-06-14 22:42:22

标签: c# inheritance override abstract derived

我有四节课。 Request,DerivedRequest,Handler,DerivedHandler。 Handler类具有一个具有以下声明的属性:

public abstract Request request { get; set; }

DerivedHandler需要覆盖此属性,以便它返回DerivedRequest:

public override DerivedRequest request { get; set; }

有没有人对如何使这项工作有任何想法?

6 个答案:

答案 0 :(得分:18)

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

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

答案 1 :(得分:6)

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

答案 2 :(得分:5)

除隐藏原始财产外:

public new DerivedRequest Request { get;set;}

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

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

相反,制作另一个属性:

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

通过这种方式,您对OOP保持清醒,并以明确的方式获取您的信息。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

这在理论上是不可能的。对于返回类型,覆盖必须是协变的(即,返回类型必须更具体或相同),并且参数的反变量(即,参数类型必须更不具体或相同)。所以你的新类型必须与Request有效地协变和反变 - 这意味着,唯一可能的类型只是Request

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

答案 5 :(得分:0)

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