Enum «Наследование»

391

У меня есть перечисление в низкоуровневом пространстве имен. Я хотел бы предоставить класс или перечисление в пространстве имен среднего уровня, которое «наследует» перечисление низкого уровня.

namespace low
{
   public enum base
   {
      x, y, z
   }
}

namespace mid
{
   public enum consume : low.base
   {
   }
}

Я надеюсь, что это возможно, или, возможно, какой-то класс, который может заменить потребление перечисления, который обеспечит уровень абстракции для перечисления, но все же позволит экземпляру этого класса получить доступ к перечислению.

Мысли?

РЕДАКТИРОВАТЬ: Одна из причин, по которой я не просто переключил это на conts в классах, заключается в том, что перечисление низкого уровня необходимо для службы, которую я должен потреблять. Мне дали WSDL и XSD, которые определяют структуру как перечисление. Услуга не может быть изменена.

CodeMonkey1313
источник
1
Одним из вариантов является codeproject.com/Articles/20805/Enhancing-C-Enums
Уолтер Веховен,

Ответы:

462

Это невозможно. Перечисления не могут наследоваться от других перечислений. На самом деле все перечисления должны наследоваться от System.Enum. C # позволяет синтаксису изменять базовое представление значений перечисления, которое выглядит как наследование, но в действительности они все еще наследуются от System.enum.

См. Раздел 8.5.2 спецификации CLI для полной информации. Соответствующая информация из спецификации

  • Все перечисления должны происходить из System.Enum
  • Из-за вышеизложенного все перечисления являются типами значений и, следовательно, запечатаны
JaredPar
источник
2
И все типы значений являются производными от System.ValueType
Раз Мегрелидзе
4
Должен отметить, что ответ @Seven является законным обходным
путем
но ответ @ Стивена не может быть использован в данной switchситуации.
zionpi
@zionpi да, но обратите внимание, что (я полагаю) стандартный переключатель компилируется в тот же код IL, что и полный блок if, else if, else: что, я думаю, в любом случае имеет лучший лучший синтаксис. Вы теряете способность resharper / VS автоматически завершать все заявления по делу, но я думаю, что это не конец света. Это личное предпочтение, но я не фанат заявления переключателя.
MemeDeveloper
165

Вы можете достичь того, что вы хотите с классами:

public class Base
{
    public const int A = 1;
    public const int B = 2;
    public const int C = 3;
}
public class Consume : Base
{
    public const int D = 4;
    public const int E = 5;
}

Теперь вы можете использовать эти классы аналогично тому, как они были перечислениями:

int i = Consume.B;

Обновление (после обновления вопроса):

Если вы присваиваете константы тем же значениям int, которые определены в существующем перечислении, вы можете привести между перечислением и константами, например:

public enum SomeEnum // this is the existing enum (from WSDL)
{
    A = 1,
    B = 2,
    ...
}
public class Base
{
    public const int A = (int)SomeEnum.A;
    //...
}
public class Consume : Base
{
    public const int D = 4;
    public const int E = 5;
}

// where you have to use the enum, use a cast:
SomeEnum e = (SomeEnum)Consume.B;
M4N
источник
8
Как вы тогда перечислите поля в этом классе? Для меня это важно поведение перечисления:Enum.GetValues(typeof(MyEnum)
Майк де Клерк
1
Вы можете использовать отражение: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
Mnieto
2
Вы должны убедиться, что сбор свойств с отражением игнорирует унаследованные свойства объекта.
Роберт
Отражение супер уродливо для этой задачи.
dylanh724
1
Нет необходимости использовать Reflection, реализация на codeproject.com/Articles/20805/Enhancing-C-Enums - хороший способ сделать это, поскольку объекты создаются, они добавляются в список, и этот список можно использовать для вернуть список типов объектов. Когда вы смешиваете это с наследованием, вам нужно убедиться, что вы используете правильный список для наследующих классов.
PBo
112

Краткий ответ: нет. Вы можете немного поиграть, если хотите:

Вы всегда можете сделать что-то вроде этого:

private enum Base
{
    A,
    B,
    C
}

private enum Consume
{
    A = Base.A,
    B = Base.B,
    C = Base.C,
    D,
    E
}

Но это не работает так здорово, потому что Base.A! = Consume.A

Вы всегда можете сделать что-то вроде этого, хотя:

public static class Extensions
{
    public static T As<T>(this Consume c) where T : struct
    {
        return (T)System.Enum.Parse(typeof(T), c.ToString(), false);
    }
}

Для того, чтобы перейти между Base и Consume ...

Вы также можете привести значения перечислений как целые и сравнивать их как целые, а не как перечисление, но это тоже отстой.

Возвращаемым методом расширения должен быть тип cast типа T.

Брайан Дженисио
источник
4
Я копаю это, чувак. Использовал эту концепцию для передачи некоторых перечислений из моего ORM в мой открытый интерфейс (для тех, у кого нет ссылки на ORM).
ObjectType
5
Можно сравнивать перечисления для сравнения с работой:Base.A == (Base)Consume.A
Kresimir
1
Использовать (десятичное) Base.A == (десятичное) Consume.A. Причина: так работает объединение битовых флагов и масок (например, в Enum.IsDefined msdn.microsoft.com/en-us/library/… ). Таким образом, enum может быть установлен на целое число, не определенное в enum. Потребление теста = 123456;
TamusJRoyce
3
@TamusJRoyce десятичный? intбыло бы намного больше смысла. Когда перечисление будет иметь дробную часть!?!?!
ErikE
По крайней мере, это гарантирует, что соответствующие константы перечисления имеют одинаковое целочисленное значение. В конце концов, перечисления - это просто набор целочисленных констант. C # не требует, чтобы назначенные значения были константами перечисления vaild, то есть перечисления не являются типобезопасными в строгом смысле.
Оливье Жако-Дескомб
98

В приведенных выше решениях с использованием классов с константами int отсутствует безопасность типов. Т.е. вы можете изобрести новые значения, которые на самом деле не определены в классе. Кроме того, невозможно, например, написать метод, принимающий один из этих классов в качестве входных данных.

Вам нужно будет написать

public void DoSomethingMeaningFull(int consumeValue) ...

Тем не менее, существует классическое решение старых времен Java, когда не было доступных перечислений. Это обеспечивает почти подобное перечислению поведение. Единственное предостережение в том, что эти константы не могут быть использованы внутри оператора switch.

public class MyBaseEnum
{
    public static readonly MyBaseEnum A = new MyBaseEnum( 1 );
    public static readonly MyBaseEnum B = new MyBaseEnum( 2 );
    public static readonly MyBaseEnum C = new MyBaseEnum( 3 );

    public int InternalValue { get; protected set; }

    protected MyBaseEnum( int internalValue )
    {
        this.InternalValue = internalValue;
    }
}

public class MyEnum : MyBaseEnum
{
    public static readonly MyEnum D = new MyEnum( 4 );
    public static readonly MyEnum E = new MyEnum( 5 );

    protected MyEnum( int internalValue ) : base( internalValue )
    {
        // Nothing
    }
}

[TestMethod]
public void EnumTest()
{
    this.DoSomethingMeaningful( MyEnum.A );
}

private void DoSomethingMeaningful( MyBaseEnum enumValue )
{
    // ...
    if( enumValue == MyEnum.A ) { /* ... */ }
    else if (enumValue == MyEnum.B) { /* ... */ }
    // ...
}
Семь
источник
7
Я думаю, что это правильный ответ. Вы не можете иметь наследство для Enum, но это может позволить вам управлять им!
Робоб
11
Красиво и чисто. +1. Просто подсказка, вам действительно не нужно значение int вообще.
Игнасио Солер Гарсия
1
Я никогда не думал о перечислениях, как будто вы можете сказать FileOpenMode.Read> FileOpenMode.Write. Если это так, то вам нужен int или даже лучше IEqualityComparer для этого перечисления. С уважением.
Игнасио Солер Гарсия
3
@binki, использующее random object, делало бы значения разными для каждого экземпляра сборки, поэтому их нельзя сериализовать.
ivan_pozdeev
2
Но это не позволяет вам «включить» MyEnum, не так ли? Я имею в виду, что именно поэтому я использую перечисления ...
MemphiZ
13

Игнорируя тот факт, что база является зарезервированным словом, вы не можете делать наследование enum.

Лучшее, что вы можете сделать, это что-то вроде этого:

public enum Baseenum
{
   x, y, z
}

public enum Consume
{
   x = Baseenum.x,
   y = Baseenum.y,
   z = Baseenum.z
}

public void Test()
{
   Baseenum a = Baseenum.x;
   Consume newA = (Consume) a;

   if ((Int32) a == (Int32) newA)
   {
   MessageBox.Show(newA.ToString());
   }
}

Поскольку все они имеют один и тот же базовый тип (то есть: int), вы можете присвоить значение из экземпляра одного типа другому, который был приведен. Не идеально, но это работает.

паскаль
источник
2
база зарезервирована, но база не
erikkallen
2
Он ссылается на использование ОП в качестве имени перечисления, это просто пример имени, я уверен
Джон Раш
То же, что и ответ Дженисио.
nawfal
6

Я знаю, что этот ответ немного запоздал, но вот что я в итоге сделал:

public class BaseAnimal : IEquatable<BaseAnimal>
{
    public string Name { private set; get; }
    public int Value { private set; get; }

    public BaseAnimal(int value, String name)
    {
        this.Name = name;
        this.Value = value;
    }

    public override String ToString()
    {
        return Name;
    }

    public bool Equals(BaseAnimal other)
    {
        return other.Name == this.Name && other.Value == this.Value;
    }
}

public class AnimalType : BaseAnimal
{
    public static readonly BaseAnimal Invertebrate = new BaseAnimal(1, "Invertebrate");

    public static readonly BaseAnimal Amphibians = new BaseAnimal(2, "Amphibians");

    // etc        
}

public class DogType : AnimalType
{
    public static readonly BaseAnimal Golden_Retriever = new BaseAnimal(3, "Golden_Retriever");

    public static readonly BaseAnimal Great_Dane = new BaseAnimal(4, "Great_Dane");

    // etc        
}

Тогда я могу делать такие вещи, как:

public void SomeMethod()
{
    var a = AnimalType.Amphibians;
    var b = AnimalType.Amphibians;

    if (a == b)
    {
        // should be equal
    }

    // call method as
    Foo(a);

    // using ifs
    if (a == AnimalType.Amphibians)
    {
    }
    else if (a == AnimalType.Invertebrate)
    {
    }
    else if (a == DogType.Golden_Retriever)
    {
    }
    // etc          
}

public void Foo(BaseAnimal typeOfAnimal)
{
}
Тоно Нам
источник
2
Магические числа могут быть заменены объектами согласно stackoverflow.com/questions/757684/… . Но в этом конкретном случае вы можете получить лучшее из обоих миров, используя возможности существующей биологической номенклатуры, чтобы гарантировать уникальность.
ivan_pozdeev
4

Это то, что я сделал. То, что я сделал по-другому, это используйте одно и то же имя и newключевое слово для «потребления» enum. Поскольку имя enumодно и то же, вы можете просто бездумно использовать его, и оно будет правильным. Плюс вы получаете intellisense. При настройке нужно просто позаботиться о том, чтобы значения копировались из базы, и синхронизировать их. Вы можете помочь этому наряду с комментариями кода. Это еще одна причина, почему в базе данных при хранении enumзначений я всегда сохраняю строку, а не значение. Потому что, если вы используете автоматически назначаемые увеличивающиеся целочисленные значения, они могут меняться со временем.

// Base Class for balls 
public class BaseBall
{
    // keep synced with subclasses!
    public enum Sizes
    {
        Small,
        Medium,
        Large
    }
}

public class VolleyBall : BaseBall
{
    // keep synced with base class!
    public new enum Sizes
    {
        Small = BaseBall.Sizes.Small,
        Medium = BaseBall.Sizes.Medium,
        Large = BaseBall.Sizes.Large,
        SmallMedium,
        MediumLarge,
        Ginormous
    }
}
toddmo
источник
2
Рассмотрите возможность установки другого диапазона для новых значений в производном классе (например SmallMedium = 100,), чтобы вы могли сохранять совместимость со старыми версиями вашего программного обеспечения при добавлении новых значений в базовый класс. Например, добавление Hugeразмера в базовое перечисление присваивает 4его значению, но 4уже занято SmallMediumв производном классе.
Роберто
1
@Roberto, для решения этой проблемы я никогда не сохраняю значения enum, а только имена. И держать их синхронизированными является обязательным требованием. Так что добавление Hugeв базовый класс потребовало бы Hugeв подклассе раньшеSmallMedium
toddmo
2
BaseBallможет быть, не самое умное имя здесь. Это сбивает с толку. Поскольку бейсбол на самом деле вещь. Если вы пропустите, что это просто базовый класс для мяча, это выглядит очень странно, что волейбол наследует от физически меньшего бейсбола :). Мое предложение просто использоватьBall
Ник Н.
3

Альтернативное решение

В моей компании мы избегаем «перепрыгивать через проекты», чтобы попасть в необычные проекты нижнего уровня. Например, наш уровень представления / API может ссылаться только на наш уровень домена, а уровень домена может ссылаться только на уровень данных.

Однако это проблема, когда есть перечисления, на которые должны ссылаться как уровни представления, так и уровни домена.

Вот решение, которое мы реализовали (пока). Это довольно хорошее решение и хорошо работает для нас. Другие ответы били все вокруг.

Основная предпосылка состоит в том, что перечисления не могут быть унаследованы - но классы могут. Так...

// In the lower level project (or DLL)...
public abstract class BaseEnums
{
    public enum ImportanceType
    {
        None = 0,
        Success = 1,
        Warning = 2,
        Information = 3,
        Exclamation = 4
    }

    [Flags]
    public enum StatusType : Int32
    {
        None = 0,
        Pending = 1,
        Approved = 2,
        Canceled = 4,
        Accepted = (8 | Approved),
        Rejected = 16,
        Shipped = (32 | Accepted),
        Reconciled = (64 | Shipped)
    }

    public enum Conveyance
    {
        None = 0,
        Feet = 1,
        Automobile = 2,
        Bicycle = 3,
        Motorcycle = 4,
        TukTuk = 5,
        Horse = 6,
        Yak = 7,
        Segue = 8
    }

Затем "наследовать" перечисления в другом проекте более высокого уровня ...

// Class in another project
public sealed class SubEnums: BaseEnums
{
   private SubEnums()
   {}
}

Это имеет три реальных преимущества ...

  1. Определения enum автоматически совпадают в обоих проектах - по определению.
  2. Любые изменения в определениях перечислений автоматически отображаются во втором, не внося никаких изменений во второй класс.
  3. Перечисления основаны на одном и том же коде - поэтому значения можно легко сравнить (с некоторыми оговорками).

Чтобы ссылаться на перечисления в первом проекте , вы можете использовать префикс класса: BaseEnums.StatusType.Pending или добавить «using static BaseEnums;» Заявление о вашем использовании.

Во втором проекте при работе с унаследованным классом, однако, я не мог заставить работать подход «используя статический ...» , поэтому все ссылки на «унаследованные перечисления» должны иметь префикс с классом, например, SubEnums.StatusType.Pending. , Если кто-нибудь придумает, как использовать «статический» подход во втором проекте, дайте мне знать.

Я уверен, что это можно изменить, чтобы сделать его еще лучше - но на самом деле это работает, и я использовал этот подход в рабочих проектах.

Пожалуйста, проголосуйте, если вы найдете это полезным.

Томас Фанеуф
источник
2

Я также хотел перегрузить Enums и создал комбинацию ответа «Семь» на этой странице и ответа «Мерлин Морган-Грэм» в дублирующем посте , а также пару улучшений.
Основные преимущества моего решения перед другими:

  • автоматическое увеличение базового значения int
  • автоматическое именование

Это готовое решение, которое может быть вставлено непосредственно в ваш проект. Он разработан для моих нужд, поэтому, если вам не нравятся некоторые его части, просто замените их собственным кодом.

Во-первых, существует базовый класс CEnum, от которого должны наследоваться все пользовательские перечисления. Он имеет базовую функциональность, аналогичную Enumтипу .net :

public class CEnum
{
  protected static readonly int msc_iUpdateNames  = int.MinValue;
  protected static int          ms_iAutoValue     = -1;
  protected static List<int>    ms_listiValue     = new List<int>();

  public int Value
  {
    get;
    protected set;
  }

  public string Name
  {
    get;
    protected set;
  }

  protected CEnum ()
  {
    CommonConstructor (-1);
  }

  protected CEnum (int i_iValue)
  {
    CommonConstructor (i_iValue);
  }

  public static string[] GetNames (IList<CEnum> i_listoValue)
  {
    if (i_listoValue == null)
      return null;
    string[] asName = new string[i_listoValue.Count];
    for (int ixCnt = 0; ixCnt < asName.Length; ixCnt++)
      asName[ixCnt] = i_listoValue[ixCnt]?.Name;
    return asName;
  }

  public static CEnum[] GetValues ()
  {
    return new CEnum[0];
  }

  protected virtual void CommonConstructor (int i_iValue)
  {
    if (i_iValue == msc_iUpdateNames)
    {
      UpdateNames (this.GetType ());
      return;
    }
    else if (i_iValue > ms_iAutoValue)
      ms_iAutoValue = i_iValue;
    else
      i_iValue = ++ms_iAutoValue;

    if (ms_listiValue.Contains (i_iValue))
      throw new ArgumentException ("duplicate value " + i_iValue.ToString ());
    Value = i_iValue;
    ms_listiValue.Add (i_iValue);
  }

  private static void UpdateNames (Type i_oType)
  {
    if (i_oType == null)
      return;
    FieldInfo[] aoFieldInfo = i_oType.GetFields (BindingFlags.Public | BindingFlags.Static);

    foreach (FieldInfo oFieldInfo in aoFieldInfo)
    {
      CEnum oEnumResult = oFieldInfo.GetValue (null) as CEnum;
      if (oEnumResult == null)
        continue;
      oEnumResult.Name = oFieldInfo.Name;
    }
  }
}

Во-вторых, здесь есть 2 производных класса Enum. Все производные классы нуждаются в некоторых основных методах, чтобы работать как положено. Это всегда один и тот же стандартный код; Я еще не нашел способ передать его в базовый класс. Код первого уровня наследования незначительно отличается от всех последующих уровней.

public class CEnumResult : CEnum
{
  private   static List<CEnumResult>  ms_listoValue = new List<CEnumResult>();

  public    static readonly CEnumResult Nothing         = new CEnumResult (  0);
  public    static readonly CEnumResult SUCCESS         = new CEnumResult (  1);
  public    static readonly CEnumResult UserAbort       = new CEnumResult ( 11);
  public    static readonly CEnumResult InProgress      = new CEnumResult (101);
  public    static readonly CEnumResult Pausing         = new CEnumResult (201);
  private   static readonly CEnumResult Dummy           = new CEnumResult (msc_iUpdateNames);

  protected CEnumResult () : base ()
  {
  }

  protected CEnumResult (int i_iValue) : base (i_iValue)
  {
  }

  protected override void CommonConstructor (int i_iValue)
  {
    base.CommonConstructor (i_iValue);

    if (i_iValue == msc_iUpdateNames)
      return;
    if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
      ms_listoValue.Add (this);
  }

  public static new CEnumResult[] GetValues ()
  {
    List<CEnumResult> listoValue = new List<CEnumResult> ();
    listoValue.AddRange (ms_listoValue);
    return listoValue.ToArray ();
  }
}

public class CEnumResultClassCommon : CEnumResult
{
  private   static List<CEnumResultClassCommon> ms_listoValue = new List<CEnumResultClassCommon>();

  public    static readonly CEnumResult Error_InternalProgramming           = new CEnumResultClassCommon (1000);

  public    static readonly CEnumResult Error_Initialization                = new CEnumResultClassCommon ();
  public    static readonly CEnumResult Error_ObjectNotInitialized          = new CEnumResultClassCommon ();
  public    static readonly CEnumResult Error_DLLMissing                    = new CEnumResultClassCommon ();
  // ... many more
  private   static readonly CEnumResult Dummy                               = new CEnumResultClassCommon (msc_iUpdateNames);

  protected CEnumResultClassCommon () : base ()
  {
  }

  protected CEnumResultClassCommon (int i_iValue) : base (i_iValue)
  {
  }

  protected override void CommonConstructor (int i_iValue)
  {
    base.CommonConstructor (i_iValue);

    if (i_iValue == msc_iUpdateNames)
      return;
    if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
      ms_listoValue.Add (this);
  }

  public static new CEnumResult[] GetValues ()
  {
    List<CEnumResult> listoValue = new List<CEnumResult> (CEnumResult.GetValues ());
    listoValue.AddRange (ms_listoValue);
    return listoValue.ToArray ();
  }
}

Классы были успешно протестированы с помощью следующего кода:

private static void Main (string[] args)
{
  CEnumResult oEnumResult = CEnumResultClassCommon.Error_Initialization;
  string sName = oEnumResult.Name;   // sName = "Error_Initialization"

  CEnum[] aoEnumResult = CEnumResultClassCommon.GetValues ();   // aoEnumResult = {testCEnumResult.Program.CEnumResult[9]}
  string[] asEnumNames = CEnum.GetNames (aoEnumResult);
  int ixValue = Array.IndexOf (aoEnumResult, oEnumResult);    // ixValue = 6
}
Тобиас Кнаусс
источник
1

Перечисления не являются реальными классами, даже если они выглядят так. Внутренне они обрабатываются так же, как и их базовый тип (по умолчанию Int32). Следовательно, вы можете сделать это только путем «копирования» отдельных значений из одного перечисления в другое и приведения их к их целому числу, чтобы сравнить их на равенство.

Лусеро
источник
1

Перечисления не могут быть получены из других перечислений, но только из int, uint, short, ushort, long, ulong, byte и sbyte.

Как сказал Паскаль, вы можете использовать другие значения или константы enum для инициализации значения enum, но это все.

Йерун Ландхир
источник
8
Это немного неправильно из-за синтаксиса c #, но enum не может на самом деле наследовать от int, uint и т. Д. Под капотом они все еще наследуют от System.Enum. Просто член, представляющий перечисление, набирается в int, uint и т. Д.
JaredPar
@JaredPar. Когда enum извлекается из uint, это означает, что все значения являются uint и т. Д. По умолчанию enum наследует int. (Взгляните на спецификацию C #, перечисление SomeEnum: uint {...} действительно работает.)
Jeroen Landheer
4
Вообще-то, нет. Он наследует System.enum. Как было опубликовано ранее и чаще здесь, то, что вы думаете, наследование - это всего лишь двусмысленность языка в csharp.
TomTom
1

другое возможное решение:

public enum @base
{
    x,
    y,
    z
}

public enum consume
{
    x = @base.x,
    y = @base.y,
    z = @base.z,

    a,b,c
}

// TODO: Add a unit-test to check that if @base and consume are aligned

НТН

ShloEmi
источник
1

Это невозможно (как уже упоминалось @JaredPar). Попытка обойти эту логику - плохая практика. Если у вас есть, у base classкоторого есть enum, вы должны перечислить все возможные enum-valuesварианты, и реализация класса должна работать со значениями, которые он знает.

Например, предположим, что у вас есть базовый класс BaseCatalog, и у него есть enum ProductFormats( Digital, Physical). Тогда вы можете иметь MusicCatalogили BookCatalogто, что может содержать оба Digitalи Physicalпродукты, но если класс ClothingCatalog, он должен содержать только Physicalпродукты.

Jaider
источник
1

Я понимаю, что немного опоздал на эту вечеринку, но вот мои два цента.

Нам всем ясно, что наследование Enum не поддерживается платформой. В этой теме были предложены некоторые очень интересные обходные пути, но ни один из них не был похож на то, что я искал, поэтому я сам попробовал.

Представляем: ObjectEnum

Вы можете проверить код и документацию здесь: https://github.com/dimi3tron/ObjectEnum .

И пакет здесь: https://www.nuget.org/packages/ObjectEnum

Или просто установите его: Install-Package ObjectEnum

Короче говоря, ObjectEnum<TEnum>действует как обертка для любого перечисления. Переопределив GetDefinedValues ​​() в подклассах, можно указать, какие значения перечисления действительны для этого конкретного класса.

Был добавлен ряд перегрузок операторов, чтобы заставить ObjectEnum<TEnum>экземпляр вести себя так, как если бы он был экземпляром базового перечисления, с учетом ограничений на определенные значения. Это означает, что вы можете легко сравнить экземпляр со значением типа int или enum и, таким образом, использовать его в случае переключателя или в любом другом условном выражении.

Я хотел бы обратиться к упомянутому выше репозиторию github за примерами и дополнительной информацией.

Я надеюсь, что вы найдете это полезным. Не стесняйтесь комментировать или открыть вопрос на GitHub для дальнейших мыслей или комментариев.

Вот несколько коротких примеров того, что вы можете сделать с ObjectEnum<TEnum>:

var sunday = new WorkDay(DayOfWeek.Sunday); //throws exception
var monday = new WorkDay(DayOfWeek.Monday); //works fine
var label = $"{monday} is day {(int)monday}." //produces: "Monday is day 1."
var mondayIsAlwaysMonday = monday == DayOfWeek.Monday; //true, sorry...

var friday = new WorkDay(DayOfWeek.Friday);

switch((DayOfWeek)friday){
    case DayOfWeek.Monday:
        //do something monday related
        break;
        /*...*/
    case DayOfWeek.Friday:
        //do something friday related
        break;
}
Дмитрий Тронкок
источник
-8

Вы можете выполнять наследование в enum, однако оно ограничено только следующими типами. int, uint, byte, sbyte, short, ushort, long, ulong

Например

public enum Car:int{
Toyota,
Benz,
}
Шриванта Аттанаяке
источник
2
Я думаю, что ОП просил наследовать одно перечисление от другого, а не только от базового числового типа (который все перечисления делают в C #, неявно или явно).
reirab