Enum "Warisan"

391

Saya memiliki enum di namespace tingkat rendah. Saya ingin memberikan kelas atau enum di namespace tingkat menengah yang "mewarisi" enum tingkat rendah.

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

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

Saya berharap ini mungkin, atau mungkin beberapa jenis kelas yang dapat menggantikan konsumsi enum yang akan memberikan lapisan abstraksi untuk enum, tetapi masih membiarkan instance kelas itu mengakses enum.

Pikiran?

EDIT: Salah satu alasan saya tidak hanya beralih ke const di kelas adalah bahwa enum tingkat rendah diperlukan oleh layanan yang harus saya konsumsi. Saya telah diberi WSDL dan XSD, yang mendefinisikan struktur sebagai enum. Layanan tidak dapat diubah.

CodeMonkey1313
sumber
1
Salah satu opsi adalah codeproject.com/Articles/20805/Enhancing-C-Enums
Walter Vehoeven

Jawaban:

462

Ini tidak mungkin. Enum tidak dapat diwarisi dari enum lainnya. Sebenarnya semua enum harus benar-benar mewarisi dari System.Enum. C # memungkinkan sintaks untuk mengubah representasi yang mendasari nilai enum yang tampak seperti warisan, tetapi dalam kenyataannya mereka masih mewarisi dari System.enum.

Lihat bagian 8.5.2 dari spesifikasi CLI untuk detail selengkapnya. Informasi yang relevan dari spesifikasi

  • Semua enum harus berasal System.Enum
  • Karena hal di atas, semua enum adalah tipe nilai dan karenanya disegel
JaredPar
sumber
2
Dan semua tipe nilai berasal dari System.ValueType
Raz Megrelidze
4
Harus menyebutkan bahwa jawaban @Seven adalah solusi yang sah: stackoverflow.com/a/4042826/538387
Tohid
tapi jawaban @ Steven tidak bisa digunakan dalam switchsituasi.
zionpi
@ zionpi ya tapi perhatikan bahwa (saya percaya) saklar standar dikompilasi ke dalam kode IL yang sama sebagai penuh jika, kalau tidak, kalau tidak blok lain akan: yang saya pikir memiliki sintaks yang lebih baik lebih baik pula. Anda kehilangan kemampuan untuk resharper / VS untuk melengkapi semua pernyataan kasus secara otomatis, tapi saya pikir itu bukan akhir dari dunia. Ini adalah preferensi pribadi tetapi saya bukan penggemar pernyataan beralih.
MemeDeveloper
165

Anda dapat mencapai apa yang Anda inginkan dengan kelas:

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;
}

Sekarang Anda dapat menggunakan kelas-kelas ini sama seperti ketika mereka enum:

int i = Consume.B;

Pembaruan (setelah pembaruan pertanyaan Anda):

Jika Anda menetapkan nilai int yang sama ke konstanta seperti yang didefinisikan dalam enum yang ada, maka Anda dapat melemparkan antara enum dan konstanta, misalnya:

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
sumber
8
Bagaimana Anda menghitung bidang di kelas ini? Bagi saya itu adalah perilaku penting enum:Enum.GetValues(typeof(MyEnum)
Mike de Klerk
1
Anda dapat menggunakan refleksi: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
mnieto
2
Anda harus memastikan bahwa pengumpulan properti dengan refleksi mengabaikan properti Objek yang diwarisi.
Robert
Refleksi sangat jelek untuk tugas itu.
dylanh724
1
Tidak perlu menggunakan Refleksi, implementasi di codeproject.com/Articles/20805/Enhancing-C-Enums adalah cara yang baik untuk melakukannya, karena objek sedang dibuat, mereka ditambahkan ke daftar dan daftar itu dapat digunakan untuk mengembalikan daftar jenis objek. Ketika Anda mencampurnya dengan warisan, Anda harus memastikan Anda menggunakan daftar yang tepat untuk kelas-kelas yang diwariskan.
PBo
112

Jawaban singkatnya adalah tidak. Anda bisa bermain sedikit, jika Anda mau:

Anda selalu dapat melakukan sesuatu seperti ini:

private enum Base
{
    A,
    B,
    C
}

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

Tapi, itu tidak berfungsi dengan baik karena Base.A! = Mengkonsumsi

Anda selalu dapat melakukan hal seperti ini:

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);
    }
}

Untuk melintasi antara Basis dan Konsumsi ...

Anda juga bisa melemparkan nilai-nilai enum sebagai int, dan membandingkannya sebagai int bukan enum, tetapi jenis itu juga menyebalkan.

Metode ekstensi kembali harus ketik cor itu ketik T.

Brian Genisio
sumber
4
Saya menggali ini, bung. Menggunakan konsep ini untuk menggelembungkan beberapa enum dari ORM saya ke antarmuka publik saya (kepada mereka yang tidak memiliki referensi ORM).
ObjectType
5
Satu dapat melemparkan enum untuk perbandingan untuk bekerja:Base.A == (Base)Consume.A
Kresimir
1
Gunakan Basis (desimal). A == (desimal) Mengkonsumsi. Alasan: Beginilah cara menggabungkan bit flag / mask (mis. Contoh dalam Enum.IsDefined msdn.microsoft.com/en-us/library/… ). Jadi enum dapat diatur ke integer yang tidak didefinisikan dalam enum. Uji konsumsi = 123456;
TamusJRoyce
3
@TamusJRoyce desimal? intakan lebih masuk akal. Kapan sebuah enum memiliki bagian fraksional!?!?!
ErikE
Setidaknya, ini memastikan bahwa konstanta enum yang sesuai memiliki nilai integer yang sama. Bagaimanapun, enum hanyalah seperangkat konstanta integer. C # tidak menegaskan bahwa nilai yang ditetapkan adalah konstanta vaild enum, yaitu enum tidak diketik aman dalam arti yang ketat.
Olivier Jacot-Descombes
98

Solusi di atas menggunakan kelas dengan konstanta int tidak memiliki tipe keselamatan. Yaitu Anda bisa menemukan nilai-nilai baru yang sebenarnya tidak didefinisikan di kelas. Selain itu tidak mungkin misalnya untuk menulis metode yang mengambil salah satu dari kelas-kelas ini sebagai input.

Anda harus menulis

public void DoSomethingMeaningFull(int consumeValue) ...

Namun, ada solusi berbasis kelas dari masa lalu Jawa, ketika tidak ada enum yang tersedia. Ini memberikan perilaku yang hampir seperti enum. Satu-satunya peringatan adalah bahwa konstanta ini tidak dapat digunakan dalam pernyataan 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) { /* ... */ }
    // ...
}
Tujuh
sumber
7
Saya pikir ini adalah jawaban yang tepat. Anda tidak dapat memiliki warisan untuk Enum tetapi ini memungkinkan Anda untuk mengelolanya!
robob
11
Bagus dan bersih. +1. Sekedar petunjuk, Anda benar-benar tidak membutuhkan nilai int sama sekali.
Ignacio Soler Garcia
1
Saya tidak pernah memikirkan enumerasi seolah-olah Anda bisa mengatakan FileOpenMode.Read> FileOpenMode.Write. Jika itu masalahnya maka Anda memerlukan int atau bahkan IEqualityComparer yang lebih baik untuk enum itu. Salam.
Ignacio Soler Garcia
3
@binki menggunakan random objectakan membuat nilai berbeda untuk setiap instantiation dari perakitan sehingga mereka tidak bisa serial.
ivan_pozdeev
2
Tapi ini tidak memungkinkan Anda untuk "mengaktifkan" MyEnum, bukan? Maksud saya, itulah mengapa saya menggunakan enum ...
MemphiZ
13

Mengabaikan fakta bahwa basis adalah kata yang dilindungi undang-undang, Anda tidak dapat melakukan pewarisan enum.

Hal terbaik yang dapat Anda lakukan adalah sesuatu seperti itu:

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());
   }
}

Karena semuanya adalah tipe basis yang sama (yaitu: int), Anda dapat menetapkan nilai dari instance dari satu tipe ke yang lainnya yang dilemparkan. Tidak ideal tetapi berhasil.

Pascal
sumber
2
basis dicadangkan tetapi Pangkalan tidak
erikkallen
2
Dia mengacu pada penggunaan OP dasar sebagai nama enum, itu hanya sebuah nama contoh saya yakin
John Rasch
Sama seperti jawaban Genisio.
nawfal
6

Saya tahu jawaban ini agak terlambat tetapi inilah yang akhirnya saya lakukan:

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        
}

Maka saya dapat melakukan hal-hal seperti:

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)
{
}
Tono Nam
sumber
2
Angka ajaib dapat diganti dengan objek sesuai stackoverflow.com/questions/757684/… . Tetapi untuk kasus khusus ini, Anda bisa mendapatkan yang terbaik dari kedua dunia dengan menggunakan fitur nomenklatur biologis yang ada untuk menjamin keunikan.
ivan_pozdeev
4

Inilah yang saya lakukan. Apa yang saya lakukan berbeda adalah menggunakan nama dan newkata kunci yang sama pada "mengkonsumsi" enum. Karena nama enumitu sama, Anda bisa menggunakannya tanpa pikir panjang dan itu akan benar. Plus Anda mendapatkan Intellisense. Anda hanya perlu berhati-hati saat mengaturnya agar nilai-nilai disalin dari pangkalan dan tetap disinkronkan. Anda dapat membantu itu bersama dengan komentar kode. Ini adalah alasan lain mengapa dalam database ketika menyimpan enumnilai, saya selalu menyimpan string, bukan nilai. Karena jika Anda menggunakan peningkatan nilai integer yang ditetapkan secara otomatis, nilai itu dapat berubah seiring waktu.

// 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
sumber
2
Pertimbangkan pengaturan rentang yang berbeda untuk nilai-nilai baru di kelas turunan (mis. SmallMedium = 100,), Sehingga Anda dapat menjaga kompatibilitas dengan versi lama dari perangkat lunak Anda ketika Anda menambahkan nilai-nilai baru di kelas dasar. Misalnya, menambahkan Hugeukuran di enum dasar Anda akan menetapkan 4nilainya, tetapi 4sudah diambil SmallMediumdi kelas turunan.
Roberto
1
@Roberto, Untuk mengatasinya, saya tidak pernah mempertahankan nilai enum, tetapi hanya nama. Dan menjaga mereka tetap disinkronkan adalah persyaratan di sini. Jadi menambahkan Hugedi kelas dasar akan perlu Hugedi subclass sebelumSmallMedium
toddmo
2
BaseBallmungkin bukan nama yang paling cerdas di sini. Ini membingungkan. Karena bisbol sebenarnya adalah sesuatu. Jika Anda melewatkan bahwa ini hanya kelas dasar untuk bola, terlihat sangat aneh bahwa bola voli mewarisi dari baseball yang secara fisik lebih kecil :). Saran saya adalah gunakan sajaBall
Nick N.
3

Solusi alternatif

Di perusahaan saya, kami menghindari "melompati proyek" untuk mencapai proyek tingkat rendah yang tidak umum. Misalnya, lapisan presentasi / API kami hanya dapat mereferensikan lapisan domain kami, dan lapisan domain hanya dapat mereferensikan lapisan data.

Namun, ini merupakan masalah ketika ada enum yang perlu direferensikan oleh presentasi dan lapisan domain.

Inilah solusi yang telah kami terapkan (sejauh ini). Ini adalah solusi yang cukup bagus dan bekerja dengan baik untuk kita. Jawaban lain mengenai semua ini.

Premis dasarnya adalah bahwa enum tidak dapat diwarisi - tetapi kelas dapat. Begitu...

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

Kemudian, untuk "mewarisi" enum di proyek tingkat yang lebih tinggi ...

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

Ini memiliki tiga keunggulan nyata ...

  1. Definisi enum secara otomatis sama di kedua proyek - menurut definisi.
  2. Setiap perubahan pada definisi enum secara otomatis digaungkan di detik tanpa harus membuat modifikasi ke kelas kedua.
  3. Enum didasarkan pada kode yang sama - sehingga nilainya dapat dengan mudah dibandingkan (dengan beberapa peringatan).

Untuk referensi enum di proyek pertama , Anda bisa menggunakan awalan kelas: BaseEnums.StatusType.Pending atau tambahkan "using static BaseEnums;"pernyataan untuk usings Anda.

Namun dalam proyek kedua ketika berhadapan dengan kelas yang diwarisi, saya tidak bisa mendapatkan pendekatan "using static ..." untuk bekerja, jadi semua referensi ke "enum yang diwariskan" akan diawali dengan kelas, misalnya SubEnums.StatusType.Pending . Jika ada yang datang dengan cara untuk memungkinkan "menggunakan statis" untuk digunakan dalam proyek kedua, beri tahu saya.

Saya yakin ini bisa diubah untuk membuatnya lebih baik - tetapi ini benar-benar berfungsi dan saya telah menggunakan pendekatan ini dalam proyek-proyek yang sedang berjalan.

Harap pilih ini jika Anda merasa terbantu.

Thomas Phaneuf
sumber
2

Saya juga ingin membebani Enums dan menciptakan campuran jawaban 'Tujuh' di halaman ini dan jawaban 'Merlyn Morgan-Graham' pada pos duplikat ini , ditambah beberapa perbaikan.
Keuntungan utama dari solusi saya daripada yang lain:

  • kenaikan otomatis dari nilai int yang mendasarinya
  • penamaan otomatis

Ini adalah solusi out-of-the-box dan dapat langsung dimasukkan ke dalam proyek Anda. Ini dirancang untuk kebutuhan saya, jadi jika Anda tidak suka beberapa bagian, ganti saja dengan kode Anda sendiri.

Pertama, ada kelas dasar CEnumyang harus diwarisi dari semua enum khusus. Ini memiliki fungsi dasar, mirip dengan Enumtipe .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;
    }
  }
}

Kedua, berikut adalah 2 kelas Enum yang diturunkan. Semua kelas turunan membutuhkan beberapa metode dasar untuk bekerja seperti yang diharapkan. Itu selalu kode boilerplate yang sama; Saya belum menemukan cara untuk melakukan outsourcing ke kelas dasar. Kode tingkat pewarisan pertama sedikit berbeda dari semua tingkatan selanjutnya.

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 ();
  }
}

Kelas telah berhasil diuji dengan kode follwing:

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
}
Tobias Knauss
sumber
1

Enum bukan kelas yang sebenarnya, bahkan jika mereka terlihat seperti itu. Secara internal, mereka diperlakukan sama seperti tipe yang mendasarinya (secara default Int32). Oleh karena itu, Anda hanya dapat melakukan ini dengan "menyalin" nilai tunggal dari satu enum ke yang lain dan melemparkannya ke nomor bilangan bulat untuk membandingkannya untuk kesetaraan.

Lucero
sumber
1

Enum tidak dapat diturunkan dari enum lain, tetapi hanya dari int, uint, pendek, ushort, panjang, ulong, byte dan sbyte.

Seperti kata Pascal, Anda dapat menggunakan nilai atau konstanta enum lain untuk menginisialisasi nilai enum, tetapi hanya itu saja.

Jeroen Landheer
sumber
8
Agak keliru karena sintaksis c # tetapi enum tidak dapat benar-benar mewarisi dari int, uint, dll ... Di bawah tenda mereka masih mewarisi dari System.Enum. Hanya saja bahwa anggota yang mewakili enum diketik ke int, uint, dll ...
JaredPar
@JaredPar. Ketika sebuah enum diturunkan dari suatu uint, itu berarti nilainya adalah semua uint, dll. Secara default enum mewarisi int. (Lihatlah spesifikasi C #, enum SomeEnum: uint {...} benar-benar berfungsi.)
Jeroen Landheer
4
Sebenarnya tidak. Itu mewarisi System.enum. Seperti yang diposting sebelumnya dan lebih sering di sini, apa yang Anda pikirkan adalah warisan hanyalah sebuah dusambiguitas langauge di csharp.
TomTom
1

solusi lain yang mungkin:

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

HTH

ShloEmi
sumber
1

Ini tidak mungkin (seperti @JaredPar sudah sebutkan). Mencoba menerapkan logika untuk mengatasi ini adalah praktik yang buruk. Jika Anda memiliki base classyang memiliki enum, Anda harus membuat daftar semua kemungkinanenum-values sana, dan implementasi kelas harus bekerja dengan nilai-nilai yang diketahuinya.

Misalkan Anda memiliki kelas dasar BaseCatalog, dan memiliki enum ProductFormats( Digital, Physical). Maka Anda dapat memiliki MusicCatalogatau BookCatalogyang dapat mengandung keduanya Digitaldan Physicalproduk, tetapi jika kelasnya adalah ClothingCatalog, itu seharusnya hanya berisi Physicalproduk.

Jaider
sumber
1

Saya sadar saya agak terlambat ke pesta ini, tapi ini dua sen saya.

Kita semua jelas bahwa warisan Enum tidak didukung oleh kerangka kerja. Beberapa solusi yang sangat menarik telah disarankan di utas ini, tetapi tidak ada yang merasa seperti apa yang saya cari, jadi saya harus mencobanya sendiri.

Memperkenalkan: ObjectEnum

Anda dapat memeriksa kode dan dokumentasi di sini: https://github.com/dimi3tron/ObjectEnum .

Dan paketnya di sini: https://www.nuget.org/packages/ObjectEnum

Atau cukup instal: Install-Package ObjectEnum

Pendeknya, ObjectEnum<TEnum> bertindak sebagai pembungkus untuk enum apa pun. Dengan mengesampingkan GetDefinedValues ​​() dalam subclass, seseorang dapat menentukan nilai enum mana yang valid untuk kelas spesifik ini.

Sejumlah kelebihan operator telah ditambahkan untuk membuat ObjectEnum<TEnum> instance berperilaku seolah-olah itu adalah instance dari enum yang mendasari, dengan mengingat batasan nilai yang ditentukan. Ini berarti Anda dapat dengan mudah membandingkan instance ke nilai int atau enum, dan dengan demikian menggunakannya dalam casing atau kondisional lainnya.

Saya ingin merujuk pada repo github yang disebutkan di atas untuk contoh dan info lebih lanjut.

Saya harap Anda menemukan ini berguna. Jangan ragu untuk berkomentar atau membuka masalah di github untuk pemikiran atau komentar lebih lanjut.

Berikut adalah beberapa contoh singkat tentang apa yang dapat Anda lakukan dengan 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;
}
Dimitri Troncquo
sumber
-8

Anda dapat melakukan pewarisan di enum, namun terbatas hanya pada tipe berikut. int, uint, byte, sbyte, pendek, ushort, panjang, ulong

Misalnya

public enum Car:int{
Toyota,
Benz,
}
Sriwantha Attanayake
sumber
2
Saya pikir OP meminta untuk mewarisi satu enum dari yang lain, bukan hanya dari tipe numerik dasar (yang dilakukan semua enum dalam C #, baik secara implisit atau eksplisit.)
reirab