C #: Создание перечислений в стиле Java с наследованием - PullRequest
3 голосов
/ 09 сентября 2011

Я хочу построить шаблон перечисления в стиле Java для C #, который также поддерживает наследование.У меня проблемы с доходностью.В частности, возвращая значения BaseEnum из свойства значений ChildEnum.

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

Ответы [ 3 ]

1 голос
/ 09 сентября 2011
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)
    {
    }
} 
1 голос
/ 09 сентября 2011

Используйте

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

Вам нужно развернуть BaseEnum.Values ​​в отдельные элементы.

Или замените его выражением LINQ: -

return BaseEnum.Values.Concat(new[]{ D, E });
0 голосов
/ 09 сентября 2011

Вот версия, которая избавляет от необходимости иметь неприятный перечислитель 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 только код, работающий в иерархии наследования, можетзадайте имя, поэтому, если экземпляр появился без имени, вы знаете, что кто-то что-то делает не так.

...