c#:用继承构建java风格的枚举

本文关键字:风格 枚举 java 构建 继承 | 更新日期: 2023-09-27 18:07:57

我希望为c#构建一个java风格的枚举模式,也支持继承。我在收益回报方面遇到了麻烦。具体来说,从child 's Values属性返回BaseEnum的值。

public class BaseEnum {
    public static readonly BaseEnum A = new BaseEnum("A");
    public static readonly BaseEnum B = new BaseEnum("B");
    public static readonly BaseEnum C = new BaseEnum("C");
    public static IEnumerable<BaseEnum> Values {
        get {
            yield return A;
            yield return B;
            yield return C;
        }
    }
    public readonly String Name;
    protected BaseEnum(String name) {
        this.Name = name;
    }
    public static void TestMain() {
        Console.WriteLine("BaseEnum, should print (A,B,C):");
        foreach(BaseEnum e in BaseEnum.Values) {
            Console.WriteLine(e.Name);
        }
        Console.WriteLine("BaseEnum in ChildEnum, should print (A,B,C,D,E):");
        foreach(BaseEnum e in ChildEnum.Values) {
            Console.WriteLine(e.Name);
        }
        Console.WriteLine("ChildEnum in ChildEnum, should print (D,E):");
        foreach(ChildEnum e in ChildEnum.Values) {
            Console.WriteLine(e.Name);
        }
    }
}
class ChildEnum : BaseEnum {
    public static readonly ChildEnum D = new ChildEnum("D");
    public static readonly ChildEnum E = new ChildEnum("E");
    new public static IEnumerable<BaseEnum> Values {
        get {
            // yield return BaseEnum.Values; // This is what I want to do. It gives the error message below:
            // Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<Abra.Workshop.EnumABC>' 
            // to 'Abra.Workshop.EnumABC'. An explicit conversion exists (are you missing a cast?)
            yield return D;
            yield return E;
        }
    }
    public ChildEnum(string name)
        : base(name) {
    }
}
/* Output!
BaseEnum, should print (A,B,C):
A
B
C
BaseEnum in ChildEnum, should print (A,B,C,D,E):
D
E
ChildEnum in ChildEnum, should print (D,E):
D
E
*/

c#:用继承构建java风格的枚举

使用

foreach (var b in BaseEnum.Values)
  yield return b;

你需要打开BaseEnum。值转换为单个元素。

或者将其替换为LINQ表达式:-

return BaseEnum.Values.Concat(new[]{ D, E });
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("BaseEnum, should print (A,B,C):");
        foreach (BaseEnum e in BaseEnum.Values)
        {
            Console.WriteLine(e.Name);
        }
        Console.WriteLine("BaseEnum in ChildEnum, should print (A,B,C,D,E):");
        foreach (BaseEnum e in ChildEnum.Values)
        {
            Console.WriteLine(e.Name);
        }
        Console.WriteLine("ChildEnum in ChildEnum, should print (D,E):");
        foreach (ChildEnum e in ChildEnum.Values.Where(d => d.GetType() == typeof(ChildEnum)))
        {
            Console.WriteLine(e.Name);
        }
    }
}
public class BaseEnum
{
    public static readonly BaseEnum A = new BaseEnum("A");
    public static readonly BaseEnum B = new BaseEnum("B");
    public static readonly BaseEnum C = new BaseEnum("C");
    public static IEnumerable<BaseEnum> Values
    {
        get
        {
            yield return A;
            yield return B;
            yield return C;
        }
    }
    public readonly String Name;
    protected BaseEnum(String name)
    {
        this.Name = name;
    }
}
public class ChildEnum : BaseEnum
{
    public static readonly ChildEnum D = new ChildEnum("D");
    public static readonly ChildEnum E = new ChildEnum("E");
    new public static IEnumerable<BaseEnum> Values
    {
        get
        {
            foreach (var baseEnum in BaseEnum.Values)
                yield return baseEnum;
            yield return D;
            yield return E;
        }
    }
    public ChildEnum(string name)
        : base(name)
    {
    }
} 

这个版本不需要使用讨厌的new public static枚举器。

它确实改变了继承结构以使其工作。我想我应该把它作为一种选择。

public class BaseEnum<E> where E : BaseEnum<E>, new()
{
    public static readonly E A = new E() { Name = "A" };
    public static readonly E B = new E() { Name = "B" };
    public static readonly E C = new E() { Name = "C" };
    public string Name { get; protected set; }
    protected static IEnumerable<E> InternalValues
    {
        get
        {
            yield return A;
            yield return B;
            yield return C;
        }
    }
}
public class BaseEnum : BaseEnum<BaseEnum>
{
    public static IEnumerable<BaseEnum> Values
    {
        get { foreach (var x in InternalValues) yield return x; }
    }
}
public class ChildEnum : BaseEnum<ChildEnum>
{
    public static readonly ChildEnum D = new ChildEnum() { Name = "D" };
    public static readonly ChildEnum E = new ChildEnum() { Name = "E" };
    public static IEnumerable<ChildEnum> Values
    {
        get
        {
            foreach (var x in InternalValues) yield return x;
            yield return D;
            yield return E;
        }
    }
}

它也需要一个默认的公共构造函数,但是由于Name属性上的protected setter,只有在继承层次结构中运行的代码才能设置名称,所以如果一个实例没有名称,你就知道有人做错了。