【问题标题】:C# : Building java-style enums with inheritanceC#:使用继承构建 java 风格的枚举
【发布时间】:2011-09-09 03:15:05
【问题描述】:

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

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
*/

【问题讨论】:

  • 我能够通过在 Values get 块中使用反射来获得我想要的结果。

标签: c# inheritance enums ienumerable yield-return


【解决方案1】:

使用

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

您需要将 BaseEnum.Values 解包为单个元素。

或者用 LINQ 表达式替换它:-

return BaseEnum.Values.Concat(new[]{ D, E });

【讨论】:

  • 使用反射我能够避免列出每个单独的枚举项。
【解决方案2】:
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)
    {
    }
} 

【讨论】:

    【解决方案3】:

    这是一个不需要讨厌的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 属性上的受保护设置器,只有在继承层次结构中运行的代码才能设置名称,所以如果出现的实例没有名称,你就知道有人在做出了点问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      相关资源
      最近更新 更多