如何强制派生类覆盖基类中的枚举?

4
让我们创建一个名为NaturalFood的类,并让两个类继承自它:Fruits和Vegetables类。
 abstract class NaturalFood
{
    enum AllList
    {
        //empty list as a placeholder
    }

   protected string Name;
}

class Fruits : NaturalFood 
{
    enum AllList
    {
        Apple = 1,
        Banana = 2
    }
}

class Vegetables : NaturalFood
{
    enum AllList
    {
        Carrot = 1,
        Potatoes = 2
    }

}

我��望强制要求任何继承自NaturalFood类的类都必须声明和/或重写AllList枚举。枚举将有效地包含特定于派生类的列表。我该如何做到这一点?
编辑:我的基本要求是,每个从基类派生的类必须具有其自己的“某些东西”的列表,该列表特定于它。枚举只是创建列表的一种方式。我希望利用Enumeration所提供的智能感知、toString()等特性。
编辑2:我的例子不够实用吗?如果我将整个枚举放在基类(NaturalFood)中,我怎么知道哪些枚举值是特定于哪些派生类的?假设每个派生类都在以枚举常量的形式“发布”其所提供的内容,我想对每个派生类强制执行此约束。换句话说,我的问题是如何像描述的情况下对派生类强制执行约束?

3
这是不可能的。枚举是一种类型,而不是类的成员。在这种情况下,重写没有意义。请描述您的需求。可能有一些适当的方法来实现它。 - Steve B
枚举是常量,因此它们不能在子类中拥有自己的定义! - Nasmi Sabeer
@SteveB,我已经在我的原始帖子的编辑中描述了我的要求。 - devanalyst
2个回答

3
这是不可能的,因为枚举是类型,而不是类成员...并且它们被声明在类内部并不意味着它们是该类的成员,它们只是嵌套的。每个类都可以并且必须定义自己的private enum AllList类型...所以你实际上的代码是唯一可行的方法。 如果您想获得类似于此的内容,并且您只需要处理几个值,请坚持使用属性重写:
class A
{
    public virtual String Value
    {
        get
        {
            return "A";
        }
    }
}

class B : A
{
    public override String Value
    {
        get
        {
            return "B";
        }
    }
}

首先,枚举类型没有继承层次结构。至于第二句话,发帖者非常小心地将自己移动到了语言不支持的区域。 - TomTom
@TomTom,我的主要关注点是尝试强制执行一种“规则”。枚举只是我选择创建“列表”的一种方式。我不是为了博取好感而发布帖子。在我的简单示例背后,我有一些严肃的东西。 - devanalyst
@Zarathos,那样做并不能给我使用枚举类型所能带来的好处。 - devanalyst
2
当然不行...但相信我,真的没有办法覆盖私有枚举。除非枚举成员的值在您的代码中很重要,否则另一种方法是声明一个通用枚举,涵盖所有可能的情况。或者使用标志枚举,这样您就可以将它们组合在一起。 - Tommaso Belluzzo

3

实际上,没有必要覆盖这些值。覆盖的优势在于可以调用派生类的方法而不必知道派生类本身。

例如:

static void Main()
{
    NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
    food.SomeMethodInBaseClass(); // ok

}

static NaturalFood GetSomeFood()
{
     if(somecondition) {
         return new Fruits();
     } 
     else{
         return new Vegetables();
     }
}

public abstract class NaturalFood
{
     public abstract void SomeMethodInBaseClass();
}

public class Fruits : NaturalFood 
{       
   public override void SomeMethodInBaseClass(){
        Console.WriteLine("I'm a fruit");
    }
}

public class Vegetables : NaturalFood
{    
    public override void SomeMethodInBaseClass(){
         Console.WriteLine("I'm a vegetable");
    }   
}

现在想象一下你想要做什么。在主方法中,尝试调用AllList:

static void Main()
{
    NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
    food.SomeMethodInBaseClass(); // ok
    food.AllList.XXXX; // What? it won't compile
}

这段代码无法编译通过。编译器不知道要推断哪个具体的派生类来获取可用的枚举值。

然而,如果从基本类型中移除枚举,它就可以工作:

static void Main()
{
    NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
    food.SomeMethodInBaseClass(); // ok

    Fruits f = new Fruits();
    Console.WriteLine(    f.AllList.Apple); // Ok

    Vegetable v = new Vegetable ();
    Console.WriteLine(    v.AllList.Potatoe); // Ok


}

但正如您所看到的,您必须明确知道实际类型,因此使多态无用。
[编辑] 回答您的第二次编辑比较困难。 实际上有许多种方法来验证这种约束条件。 如果没有更多上下文,则可能很难回答。 我认为最简单的方法是为每个派生类添加一个重写属性,描述接受哪种枚举。
public enum NaturalFoodType {
    Unknown = 0,
    Apple= 1,
    Banana = 2,
    Potatoe = 3,
    Cucumber = 4
}
public abstract class NaturalFood
{
     public abstract void SomeMethodInBaseClass();
     public abstract IEnumerable<NaturalFoodType> AcceptedFoodType { get; }

     public bool IsValid(NaturalFoodType type){
          return AcceptedFootType.Contains(type);
     }
}

public class Fruits : NaturalFood 
{       
    public override void SomeMethodInBaseClass(){
        Console.WriteLine("I'm a fruit");
    }
    public override NaturalFoodType {
        get {
             yield return NaturalFoodType.Apple;
             yield return NaturalFoodType.Banana;
        }
    }
}

public class Vegetables : NaturalFood
{    
    public override void SomeMethodInBaseClass(){
         Console.WriteLine("I'm a vegetable");
    } 
    public override NaturalFoodType {
        get {
             yield return NaturalFoodType.Potatoe;
             yield return NaturalFoodType.Cucumber;
        }
    }  
}

但是说实话,它开始加入了许多管道代码,这变得相当难以阅读。你应该考虑在更高层次上解决问题,找到一个可接受的解决方案。


谢谢你的示例。很有道理。我现在已经尝试在上面的“edit2”中更简洁地描述我的要求。 - devanalyst
这是不可扩展的。派生类必须从抽象类的枚举替代中进行选择。例如,如果派生类需要 NaturalFoodType.Tomato 呢? - Ferit

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