C#: Создание перечислений в стиле Java с наследованием
Я ищу построить шаблон перечисления в стиле Java для C#, который также поддерживает наследование. У меня проблемы с доходностью. В частности, возвращая значения BaseEnum из свойства Values 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 ответа
Использование
foreach (var b in BaseEnum.Values)
yield return b;
Вам нужно развернуть BaseEnum.Values в отдельные элементы.
Или замените его выражением 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
Код только свойства, работающий в иерархии наследования, может установить имя, поэтому, если экземпляр появился без имени, вы знаете, что кто-то что-то делает не так.