【问题标题】:C#: enums and static classes cannot be inherited, so what can I use instead? [duplicate]C#:枚举和静态类不能被继承,那我可以用什么代替呢? [复制]
【发布时间】:2021-03-19 22:58:04
【问题描述】:

我最近开始在我的应用程序中使用枚举来表示常用名称。问题是枚举不能被继承。这是意图:

public enum foreignCars
   {
     Mazda = 0,
     Nissan = 1,
     Peugot = 2
   }


public enum allCars : foreignCars
   {
     BMW = 3,
     VW = 4,
     Audi = 5
   }

当然,这是不可能的。在我发现的类似问题中,人们建议为此使用类,例如:

        public static class foreignCars
    {
        int Mazda = 0;
        int Nissan = 1;
        int Peugot = 2;
    }


    public static class allCars : foreignCars
    {
        int BMW = 3;
        int VW = 4;
        int Audi = 5;
    }

但是静态类也不能被继承!因此,我必须使它们成为非静态的并创建对象,以便能够在我的应用程序中引用这些名称,这违背了整个目的。

考虑到这一点,实现我想要的最佳方式是什么 - 拥有可继承的类似枚举的实体(这样我就不必在两个枚举/类/任何东西中重复汽车品牌),而不必实例化对象吗?这里的正确方法是什么?这是我在任何其他问题中都找不到的部分,但如果我遗漏了什么,请告诉我。

编辑:我想指出,我已经查看过类似的关于枚举和静态类继承的问题,并且我完全意识到这在 C# 中是不可能的。因此,我正在寻找其他类似问题中未涉及的替代方法。

【问题讨论】:

  • 你几乎肯定在这里做错了。您实际上拥有一个事物数据库,而不是一个枚举。
  • 具有受保护构造函数和静态属性的类可能存在一些可能性,这些是可能的实例(参见dotnetfiddle.net/Us13gZ)。但我同意@DavidG 不要这样做。
  • DavidG 是对的,但是如果你想用这种方式解决你的问题,那么看看记录,我认为它们可以适合这种情况。
  • 也许您可以在静态类中使用常量,但使用嵌套代替真正的继承。所以你可以像AllCars.ForeignCars.MazdaAllCars.VW一样称呼他们

标签: c# class enums static-classes


【解决方案1】:

您遇到的一般问题是您为枚举附加了额外的含义。一旦你这样做了,它就不再是一个枚举,它是你系统中的一个概念,通常由一个对象表示。

如果不知道更多关于你在做什么,很难提供比解决方法更多的东西。但关键是您要附加的“额外”信息不属于枚举。它需要位于其他地方。我将提供一个简单的示例,该示例还有很多不足之处,但至少代表了枚举之外的概念:

public enum allCars : int
{
    // note in general this is a bad idea, you've
    // created compile time construct to hold 
    // something that can change.
    Mazda = 0,
    Nissan = 1,
    Peugot = 2,
    BMW = 3,
    VW = 4,
    Audi = 5
}

public class Car
{
    static HashSet<allCars> foreignCars = new HashSet<allCars>(
            new allCars[] { allCars.Mazda, allCars.Nissan, allCars.Peugot });

    public Car(allCars id)
    {
        this.CarId = id;
    }

    public allCars CarId { get; }
    public bool IsForeignCar => foreignCars.Contains(this.CarId);
}

我已经将“它是不是外国汽车”的想法转移到 Car 类本身中,这可能有点冒险,但它说明了一般观点。在编译时设置可以改变的东西——枚举本身和外国汽车池——通常不是很好。您可能还想从设计中重构它。

【讨论】:

    【解决方案2】:

    C# 中的枚举是一个很弱的实现。它们基本上只是命名值。 Java 的枚举更好一点,因为它们实际上是具有特殊语义的类,因此您可以实现类似于 Java 的枚举的东西...

    public sealed class Car
    {
        public static readonly Mazda = new Car(0, "Mazda", true);
        public static readonly Nissan = new Car(1, "Nissan", true);
        public static readonly Peugeot = new Car(2, "Peugeot", true);
        public static readonly BMW = new Car(3, "BMW", false);
        public static readonly VW = new Car(4, "VW", false);
        public static readonly Audi = new Car(5, "Audi", false);
    
        private Car(int value, string name, bool isForeign)
        {
            Value = value;
            Name = name;
            IsForeign = isForeign;
        }
    
        public int Value { get; }
        public string Name { get; }
        public bool IsForeign { get; }
        
        // TODO : Implement Equals and GetHashCode...
        public override string ToString() => Name;
    }
    

    请注意,这里唯一可以创建的Car 实例是在类本身中声明的,并且不能在外部构造任何实例,因为构造函数是私有的。这与 Java 中的枚举很相似,并且允许您在枚举中包含其他字段,而不仅仅是名称和值。

    这里还有一点需要注意...IsForeign 被声明为bool。对你来说陌生,对我来说可能并不陌生,所以也要考虑全球化和本地化。也许您应该通过CountryOfManufacture 指定Car,或者更好的是,来自.NET 的Culture 命名空间。

    如果您想知道我从哪里获得枚举类的灵感...Automapper 的作者 Jimmy Bogard。

    https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/

    【讨论】:

    • 尽管这可能解决了您的问题,但我会认真考虑您的实施,并可能将这些数据移动到数据库或其他东西(可变)而不是枚举(不可变)。
    • CountryOfManufacture 的另一条评论 - 可能是错误的名称,因为有些汽车是在许多国家/地区生产的。 CountryOfOrigin 提到他们的总部可能更相关......但同样,你不能相信这是一个不变的事实。
    猜你喜欢
    • 2010-10-20
    • 2015-01-19
    • 1970-01-01
    • 2011-06-27
    • 2016-05-29
    • 1970-01-01
    • 2019-08-10
    • 2011-06-02
    • 1970-01-01
    相关资源
    最近更新 更多