使用派生类覆盖基类的属性

10
在C#代码中,如果Rebar类派生自Reinforcement类,并且RebarShape类继承了ReinforcementShape类。是否可以使用RebarShape类覆盖基类中的属性ReinforcementShape
   public class ReinforcementShape
   {
   }

   public class RebarShape : ReinforcementShape
   {
   }

   public class Reinforcement
   {
        public ReinforcementShape Shape { get; set; }
   }


   public class Rebar : Reinforement
   {
        // I want to override the Shape property
        // but with its derived class which is RebarShape

        // override the base property somehow!
        public RebarShape Shape { get; set; }
   }

更新:

当前实现有什么问题?

基本实现:

public virtual ReinforcementShape Shape { get; set; }

在派生类中:

public new RebarShape Shape { get; set; }

1
你不能覆盖一个属性并改变它的返回类型。 - R.Rusev
2个回答

13

你可以使用泛型来实现这个功能,无需覆盖基类成员:

public class Reinforcement<T> where T: ReinforcementShape 
{
    public <T> Shape { get; set; }
}

public class Rebar : Reinforement<RebarShape>
{
}

现在您可以轻松创建一个ReBar的实例,并访问其Shape属性,该属性是RebarShape的一个实例:
var r = new Rebar();
r.Shape = new RebarShape();

尝试将一个ReinforcementShape的实例分配给该属性将导致编译时错误,此时只有RebarShape是有效的。

编辑:根据您的编辑。您只能通过重写其实现而不是返回值来重写成员。因此,在您的情况下使用virtual不会起作用。然而,正如R.Rusev已经提到的,您只需要在派生成员上使用new关键字,这将提供一个完全新的成员,它与基类中的那个具有相同的名称。但实际上,它是一个完全不同的成员,与以前的成员没有任何共同之处。但是当您编写以下内容时

Reinforcement r = new Rebar();
// assign value to Shape
var shape = r.Shape;

使用原始实现,而不是您的新实现。因此,shape 的类型将是 ReinforcementShape 而不是 RebarShape。唯一的解决方法是在第一次声明 r 时将其声明为 Rebar

Rebar r = new Rebar();
// assign value to Shape
var shape = r.Shape;

但是这对您的应用程序的任何用户以及可能包括您自己来说都很困惑。我通常不建议使用该关键字。最好使用第一种方法。

编辑:C#9 具有成员协变返回类型的能力。这样,您可以在 ReBar 类中使用 public RebarShape Shape { get; set; }


很不幸,我不能使用泛型。因为我需要对这些类的几个属性执行此操作。 - Vahid
@Vahid:那么你应该在你的问题中添加其他属性。一般来说,泛型是更好的方法(相比于new关键字的答案)。 - phifi

1
你可以使用new关键字来实现。因此,Rebar类的定义将如下所示。
public class Rebar : Reinforement
{
    public new RebarShape Shape
    {
        get { return (RebarShape)base.Shape; }
        set { base.Shape = value; }
    }
}

6
new 关键字并不会 覆盖(override)基类的实现,而是 隐藏(hide)它。无论如何,即使使用了 new 关键字,在你将派生类的实例作为基类变量使用时,原始成员仍然被使用,而不是新的成员。 - MakePeaceGreatAgain
谢谢。您能否向我展示基类中的实现?我也想在基类中进行设置。 - Vahid
@Vahid 基类保持不变。 - R.Rusev
@HimBromBeere 你说得对。我只是认为这就是Vahid想要做的。这样他在使用Rebar时就不必每次都转换RebarShape了。 - R.Rusev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接