【问题标题】:Overriding constants in derived classes in C#覆盖 C# 派生类中的常量
【发布时间】:2010-10-20 16:53:57
【问题描述】:

在 C# 中,可以在派生类中重写常量吗?我有一组相同的类,除了一些常量值,所以我想创建一个定义所有方法的基类,然后在派生类中设置相关常量。这可能吗?

我宁愿不只是将这些值传递给每个对象的构造函数,因为我希望增加多个类的类型安全性(因为两个具有不同常量的对象进行交互是没有意义的)。

【问题讨论】:

    标签: c# inheritance constants


    【解决方案1】:

    不幸的是,常量不能被覆盖,因为它们不是虚拟成员。编译器在编译时将代码中的常量标识符替换为其文字值。

    我建议您尝试将抽象或虚拟属性用于您想做的事情。它们是虚拟的,因此可以(在抽象属性的情况下必须)在派生类型中被覆盖。

    【讨论】:

      【解决方案2】:

      如果你想覆盖它,它不是一个常数;)。尝试虚拟只读属性(或受保护的 setter)。

      只读属性:

      public class MyClass {
          public virtual string MyConst { get { return "SOMETHING"; } }
      }
      ...
      public class MyDerived : MyClass {
          public override string MyConst { get { return "SOMETHINGELSE"; } }
      }
      

      受保护的设置器:

      public class MyClass {
          public string MyConst { get; protected set; }
      
          public MyClass() {
              MyConst = "SOMETHING";
          }
      }
      
      public class MyDerived : MyClass {
          public MyDerived() {
              MyConst = "SOMETHING ELSE";
          }
      }
      

      【讨论】:

        【解决方案3】:

        标有const 的常量不能被覆盖,因为它们在编译时被编译器替换。

        但是分配给常量值的常规静态字段可以。我刚才也遇到过这样的情况:

        class Columns
        {
            public static int MaxFactCell = 7;
        }
        
        class Columns2 : Columns
        {
            static Columns2()
            {
                MaxFactCell = 13;
            }
        }
        

        如果我只是在派生类中重新定义 MaxFactCell 字段,则多态将不起作用:使用 Columns2 作为 Columns 的代码将看不到覆盖值。

        如果您需要限制对该字段的写入(但不是读取)访问,使用readonly 将禁止在Columns2 中重新定义它。改为属性,代码稍微多一点:

        class Columns
        {
            static Columns()
            {
                MaxFactCell = 7;
            }            
            public static int MaxFactCell { get; protected set; }
        }
        
        class Columns2 : Columns
        {
            static Columns2()
            {
                MaxFactCell = 13;
            }
        }
        

        【讨论】:

        • 不能保证在访问Columns2.MacFactCell之前调用Columns2的static constructor,结果可能是7。此外,一旦调用了Columns2 构造函数(例如在创建第一个Columns2 实例时),Columns.MacFactCell 将显示为 13。
        • @marapet 怎么样?根据docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…,“在创建第一个实例或引用任何静态成员之前自动调用[静态构造函数]。” ——这就是这里发生的事情。 docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… 都没有提到两个班级的成员共享同一个空间。
        • @marapet 我确实看到了 VS2017 的 csc,正如您所说(代码是为 VS2008 和 .NET 3.5 编写的),但它似乎与文档直接矛盾!
        • 也许沿途某处发生了一些变化...MaxFactCell 似乎被认为是Columns 的成员,即使通过Columns2.MaxFactCell 访问时也是如此,因此不会调用Columns2 静态构造函数,这与文档一致。这是有道理的,因为您不能使用静态类进行继承。当 Columns2 继承 Columns 时,仅关注 Columns2 的 instances
        【解决方案4】:

        编辑:这可能会有意想不到的行为,请参阅下面 Shai Petel 的评论。

        您可以通过声明新常量new 来隐藏派生类中继承的常量。不过,我不确定这是一个好习惯。

        class A
        {
            protected const int MyConst = 1;
        }
        
        class B : A
        {
            new private const int MyConst = 2;
        }
        

        【讨论】:

        • 这个会很不错:)
        • 没试过,但在转换到基类时可能不起作用。因此,如果您有 B 类型的对象,当您将其转换/视为 A 类型的对象时,理论上它会返回 1 而不是 2,因为这不会覆盖该成员。因此,这将是一种不安全的做法 - 请记住这一点。
        • @ShaiPetel 说得好。我试过了。不能从实例中引用常量(比如instanceA.MyConst),需要写A.MyConst,这样就清楚了。但是,如果类A 有一个使用MyConst 的方法,并且该方法是从B 调用的,则它使用来自AMyConst 值。
        【解决方案5】:

        解决 dten + Tracker1 的答案,但已针对 c# 6 进行了更新

        public class MyClass {
            public virtual string MyConst =>"SOMETHING";
        }
        ...
        public class MyDerived : MyClass {
            public override string MyConst  =>"SOMETHING ELSE";
        }
        

        【讨论】:

          【解决方案6】:

          您可以强制派生类具有一个常量值(嗯,一个只读属性)

          • 创建一个包含只读属性的接口。
          • 将该接口放在基类上。

          例子:

             public interface IHasConstant
             {
                  string MyConst { get; }
             }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-04-04
            • 2014-05-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多