【问题标题】:How to override constants derived classes?如何覆盖常量派生类?
【发布时间】:2013-03-01 13:04:27
【问题描述】:

代码:

public class A {
    public const int beingSupportedRate = 0;
}

 public partial class B : A {
    public const int beingSupportedRate = 1;

}

由于性能,我希望它与 const int 一样明确。 将 virtual 放在 class A 变量 beingSupportedRate 前面会导致以下编译器错误:

The modifier 'virtual' is not valid for this item

【问题讨论】:

标签: c#


【解决方案1】:

您应该使用new 关键字显式隐藏继承的成员:

public class A
{
    public const int beingSupportedRate = 0;
}

public class B : A
{
    public new const int beingSupportedRate = 1;
}

请记住,您不能从实例访问常量成员。

Console.WriteLine(A.beingSupportedRate);
Console.WriteLine(B.beingSupportedRate);

输出:

0
1

在使用此解决方案时,您应该考虑一些问题。以如下控制台程序为例:

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B b = new B();
        C c = new C();

        a.GetBeingSupportRate();
        b.GetBeingSupportRate();
        c.GetBeingSupportRate();

        Console.Read();
    }

    public class A
    {
        public const int beingSupportedRate = 0;
        public void GetBeingSupportRate()
        {
            Console.WriteLine(beingSupportedRate);
        }
    }

    public class B : A
    {
        public new const int beingSupportedRate = 1;

    }

    public class C : B
    {

    }
}

这将为所有三个类实例输出0,因为继承的方法使用 A 中的常量值。这意味着您必须覆盖所有引用该常量的方法。

首选方法是使用具有必须实现的属性的接口,而不是为此目的使用常量。

【讨论】:

  • 这是一个糟糕的解决方案,因为如果某些类A 成员访问基常量,当某些可能调用继承自A 的成员时,整个成员将访问该类的未重用标识符不变!
  • @MatíasFidemraizer 你能换个说法吗?我不太明白你的意思。
  • @JohnWillemse 摘要:这不是覆盖。这是一个标识符重用。只需编写您自己的测试代码并实现一个方法“DoStuff”,返回A 类上的beingSupportedRate 常量的值,并创建一个B 类的实例。现在拨打DoStuff。现在做整个Console.WriteLine(b.DoStuff())。要打印什么?
  • @JohnWillemse pastebin.com/MhyPrUHm 检查此代码。这表明您的答案有多么错误(在我看来)。
  • @JohnWillemse 太棒了!现在你的答案已经完成了:D
【解决方案2】:

字段(包括常量)不能是虚拟的。这与它是一个常量无关......这只是字段的工作方式......虽然常量是隐式静态的事实使得它甚至更少可行,因为它是。

如果你想要多态行为,它必须通过一个实例成员,它是一个属性、方法或事件。

顺便说一句,我强烈怀疑您的“出于性能原因,我希望它为 const”的理由是虚假的微优化。甚至不清楚您是如何使用它的,但我非常怀疑您是否尝试过将其作为非常数并证明它太慢了。

【讨论】:

  • 我还没有证明。回到我对 C++ 的了解让我觉得运行时变量要慢得多。
  • @Mahdi:a) 这不是 C++; b) 在大多数 的情况下,无论如何都无关紧要。鉴于您甚至还没有获得想要工作的行为,因此性能是您最不关心的问题。
  • @JonSkeet 如何在继承层次结构中实现类型相关的常量?假设我有一些 UI 控件类,它们都有一些默认尺寸(即按钮的默认大小与面板不同)。有些是相互派生的,但它们的默认尺寸仅取决于控件类型(即类类型)。我的猜测是公共静态只读属性或“这只是糟糕的设计”:D。
  • 哦,我忘了。我之所以需要它作为公共常量,是因为我想在其他代码段中也像 Button.DefaultWidthPanel.DefaultWidth 一样使用它。在这种情况下会想到int.MaxValue 之类的东西,但Int32 很幸运没有带有MaxValue 常量/属性的基类。 :)
  • @RobertS.:我建议您提出一个包含所有相关细节的新问题,包括您尝试过的内容。
【解决方案3】:

其实我相信你误解了面向对象编程中多态的意义。

常量、字段和变量只是一个存储(嗯,引用,但我是从概念的角度说的)。

多态是关于改变某物的行为。重写一个常量不能改变一个行为,而是改变它的值

另外一点是常量是static,因此它不属于实例,但AppDomain 中有一个不可变的单一值,它在应用程序生命周期中仍然存在。

使用上面的语句,为什么要重写像实例成员这样的常量?你想象一下接下来的情况吗?

public class A 
{
      public virtual const int Some = 1;
}

public class B : A
{
      public override const int Some = 2;
}

public class C : A
{
     // No override here!
}

int valueOfSomeConstant = C.Some;

等一下!如果常量是静态的,C.Some 将是 2,即使 C 确实不会覆盖任何常量!

引用你的问题:

由于性能,我希望它与 const int 一样明确。 [...]

这只有一个答案:过早的优化是任何软件开发的恶魔。

As Jon Skeet said,这将是您最少的问题。

【讨论】:

    【解决方案4】:

    常量不能被覆盖,它们是常量。

    如果您希望通过扩展来更改此值,那么您需要使用较少的常量,其性质会根据上下文进行更改,例如要实现的abstract 元素或virtual 覆盖。

    【讨论】:

    • 我认为这忽略了 no 字段可以被覆盖。
    【解决方案5】:

    我猜你可以做到这一点:

    public class A 
    {
        public virtual Int32 beingSupportedRate
        { 
            get { return 0; }
        }
    }
    
    public class B : A
    {
        public override Int32 beingSupportedRate 
        {
            get { return 1; }
        }
    }
    

    【讨论】:

    • 谢谢。然而这不是一个常量。这是一个运行时属性。
    猜你喜欢
    • 2010-10-20
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    相关资源
    最近更新 更多