Enum “Kalıtım”


391

Düşük seviyeli bir isim alanında bir numaralandırma var. Orta düzey bir ad alanında, düşük düzeyli numaralandırmayı "miras alan" bir sınıf ya da numaralandırma sağlamak istiyorum.

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

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

Bunun mümkün olduğunu veya belki de numaralandırma için bir soyutlama katmanı sağlayacak enum tüketmenin yerini alabilecek bir sınıfın, ancak yine de bu sınıfın bir örneğinin numaraya erişmesine izin vereceğini umuyorum.

Düşünceler?

DÜZENLEME: Bunu sadece sınıflardaki consts'a geçirmememin nedenlerinden biri, tüketmem gereken bir hizmet için düşük düzeyli numaralandırmaya ihtiyaç duymasıdır. Bana yapıyı bir enum olarak tanımlayan WSDL'ler ve XSD'ler verildi. Hizmet değiştirilemez.


Yanıtlar:


462

Bu mümkün değil. Numaralamalar diğer numaralardan devralamaz. Aslında bütün numaralar aslında miras almak zorundadır System.Enum. C # sözdiziminin, mirasa benzeyen enum değerlerinin temel temsilini değiştirmesine izin verir, ancak gerçekte hala System.enum'dan miras alırlar.

Tüm ayrıntılar için CLI spesifikasyonunun 8.5.2 bölümüne bakın . Spesifikasyondan ilgili bilgiler

  • Tüm numaralandırmaların türetilmesi gerekir System.Enum
  • Yukarıdakilerden dolayı, tüm numaralandırmalar değer tipleridir ve dolayısıyla mühürlenmiştir

2
Ve tüm değer türleri
System.ValueType

4
@Seven'in cevabının meşru bir çözüm olduğunu belirtmeliyiz: stackoverflow.com/a/4042826/538387
Tohid

ancak @ Steven'ın cevabı switchdurum altında kullanılamaz .
zionpi

@zionpi evet ama (inanıyorum) standart anahtar bir tam olarak aynı IL kodu içine derlenir alırsanız, aksi takdirde, başka bir blok olurdu: yine de daha iyi bir sözdizimi olduğunu düşünüyorum. Resharper / VS'nin tüm vaka ifadelerini otomatik olarak tamamlaması için gevşek bir yetenek yapıyorsunuz, ancak bence bu dünyanın sonu değil. Bu kişisel bir tercih ama geçiş ifadesinin hayranı değilim.
MemeDeveloper

165

Sınıflarla istediğinizi başarabilirsiniz:

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

Artık bu sınıfları numaralandırıldıkları gibi kullanabilirsiniz:

int i = Consume.B;

Güncelleme (soruyu güncelledikten sonra):

Mevcut numarada tanımlanan sabitlere aynı int değerlerini atarsanız, numaralandırma ile sabitler arasında döküm yapabilirsiniz, örneğin:

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;

8
O zaman bu sınıftaki alanları nasıl numaralandırırsınız? Benim için bu bir enum önemli davranışıdır:Enum.GetValues(typeof(MyEnum)
Mike de Klerk

1
void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
Yansımayı

2
Yansıma ile özelliklerin toplanmasının, miras alınan Nesne özelliklerini yok saydığından emin olmanız gerekir.
Robert

Yansıma bu görev için çok çirkin.
dylanh724

1
Yansıma kullanmaya gerek yok, codeproject.com/Articles/20805/Enhancing-C-Enums adresindeki uygulama, bunu yapmak için iyi bir yoldur, nesneler oluşturulduklarından bir listeye eklenir ve bu liste aşağıdakiler için kullanılabilir: nesne türlerinin bir listesini döndürür. Devralma ile karıştırdığınızda, miras sınıfları için doğru listeyi kullandığınızdan emin olmanız gerekir.
PBo

112

Kısa cevap hayır. İsterseniz biraz oynayabilirsiniz:

Her zaman böyle bir şey yapabilirsiniz:

private enum Base
{
    A,
    B,
    C
}

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

Ama, o kadar da işe yaramıyor çünkü Base.A! = Tüket

Yine de her zaman böyle bir şey yapabilirsiniz:

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

Baz ve Tüketim arasında geçiş yapmak için ...

Ayrıca numaralandırmaların değerlerini ints olarak atayabilir ve bunları numaralandırma yerine ints olarak karşılaştırabilirsiniz, ancak bu da berbat.

Genişletme yöntemi dönüşü T türünü yazmalıdır.


4
Bunu kazarım adamım. ORM'imden genel arayüzüme (ORM referansı olmayanlara) bazı numaralandırmalar yapmak için bu kavramı kullandım.
ObjectType

5
Çalışma için karşılaştırma için numaralandırmalar yapılabilir:Base.A == (Base)Consume.A
Kresimir

1
(Ondalık) Base.A == (ondalık) Consume.A kullanın. Sebep: Bit bayrağı / maske birleştirmenin nasıl çalıştığı (örneğin, Enum.IsDefined msdn.microsoft.com/en-us/library/… ). Böylece bir numaralandırma, numarada tanımlanmayan bir tamsayıya ayarlanabilir. Tüketim testi = 123456;
TamusJRoyce

3
@TamusJRoyce ondalık? intçok daha mantıklı olurdu. Bir enumun ne zaman kesirli bir parçası olur??!?!
ErikE

En azından bu, karşılık gelen enum sabitlerinin aynı tamsayı değerine sahip olmasını sağlar. Sonuçta, numaralandırmalar sadece bir tamsayı sabitler kümesidir. C #, atanan değerlerin boş enum sabitleri olmasını zorlamaz, yani numaralandırmalar tam anlamıyla güvenli değildir.
Olivier Jacot-Descombes

98

İnt sabitleri olan sınıfları kullanan yukarıdaki çözümlerde tip güvenliği yoktur. Yani aslında sınıfta tanımlanmamış yeni değerler icat edebilirsiniz. Ayrıca, örneğin bu sınıflardan birini girdi olarak alan bir yöntem yazmak mümkün değildir.

Yazman gerekecek

public void DoSomethingMeaningFull(int consumeValue) ...

Ancak, mevcut enum'ların olmadığı Java'nın eski günlerinin sınıf tabanlı bir çözümü vardır. Bu neredeyse numaralandırma benzeri bir davranış sağlar. Tek uyarı, bu sabitlerin bir switch deyimi içinde kullanılamamasıdır.

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
bence bu doğru cevap. Enum için mirasınız olamaz, ancak bu onu yönetmenize izin verebilir!
robob

11
Güzel ve temiz. +1. Sadece bir ipucu, gerçekten int değerine ihtiyacınız yok.
Ignacio Soler Garcia

1
Numaralandırmalarda FileOpenMode.Read> FileOpenMode.Write diyebilirmişsiniz gibi düşünmemiştim. Bu durumda, o numaralandırma için bir int veya daha iyi bir IEqualityComparer gerekir. Saygılarımızla.
Ignacio Soler Garcia

3
@binki random object's kullanarak montaj her örnekleme için değerleri farklı hale getirecek böylece seri hale getirilemez.
ivan_pozdeev

2
Ancak bu MyEnum'da "geçiş yapmanıza" izin vermez, değil mi? Ben Çeteleler kullanmak yüzden çoğunlukla demek ...
MemphiZ

13

Üssün ayrılmış bir kelime olduğu gerçeğini göz ardı ederek, numaralandırma mirasını yapamazsınız.

Yapabileceğiniz en iyi şey şudur:

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

Hepsi aynı temel tür olduğundan (yani: int), bir türdeki bir örnekten, bir dökümün oluşturduğu diğerine değer atayabilirsiniz. İdeal değil ama işe yarıyor.


2
baz saklıdır, ancak Baz değil
erikkallen

2
OP'nin tabanı enum adı olarak kullanmasına atıfta bulunuyor, sadece emin olduğum bir örnek isim
John Rasch

Genisio'nun cevabı ile aynı.
nawfal

6

Bu cevabın biraz geç olduğunu biliyorum ama bunu yaptım:

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        
}

Sonra şöyle şeyler yapabilirim:

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
Sihirli sayılar stackoverflow.com/questions/757684/… uyarınca nesnelerle değiştirilebilir . Ancak bu özel durum için, benzersizliği garanti etmek için mevcut biyolojik terminolojinin özelliklerini kullanarak her iki dünyanın en iyisini elde edebilirsiniz.
ivan_pozdeev

4

Ben de öyle yaptım. Farklı yaptığım aynı adı ve new"tüketen" anahtar kelimeyi kullanmaktır enum. Adı enumaynı olduğundan, sadece dikkatsizce kullanabilirsiniz ve doğru olacak. Artı zeka alırsınız. Ayar yaparken, değerlerin tabandan kopyalanmasına ve senkronize tutulmasına dikkat etmelisiniz. Kod yorumlarıyla birlikte size yardımcı olabilirsiniz. Bu veritabanında enumdeğerleri saklarken neden değeri değil, her zaman dize saklamak başka bir nedeni . Çünkü otomatik olarak atanan artan tamsayı değerleri kullanıyorsanız bunlar zamanla değişebilir.

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

2
SmallMedium = 100,Temel sınıfa yeni değerler eklediğinizde , türetilmiş sınıftaki (ör. ) Yeni değerler için farklı bir aralık ayarlamayı düşünün . Örneğin, Hugetaban numaralandırmanıza bir boyut eklemek 4değerine atar , ancak türetilmiş sınıfta 4zaten alınır SmallMedium.
Roberto

1
@Roberto, Bunu ele almak için, enum değerlerine asla dayanamıyorum, sadece isimleri. Ve onları senkronize tutmak burada bir gerekliliktir. Yani Hugetemel sınıf eklemek Hugeönce alt sınıfta bir gerekirSmallMedium
toddmo

2
BaseBallburada en akıllı isim olmayabilir. Kafa karıştırıcı. Çünkü bir beyzbol aslında bir şeydir. Bunun sadece top için bir temel sınıf olduğunu kaçırırsanız, bir voleybolun fiziksel olarak daha küçük bir beyzboldan miras alınması çok garip görünüyor :). Benim önerim sadece kullanmakBall
Nick N.

3

Alternatif çözüm

Şirketimde, ortak olmayan alt düzey projelere ulaşmak için "projelerin üstünden atlamaktan" kaçınıyoruz. Örneğin, sunu / API katmanımız yalnızca alan katmanımıza referans verebilir ve alan katmanı yalnızca veri katmanına referans verebilir.

Ancak, hem sunu hem de etki alanı katmanları tarafından başvurulması gereken numaralandırmalar olduğunda bu bir sorundur.

İşte şimdiye kadar uyguladığımız çözüm. Oldukça iyi bir çözüm ve bizim için iyi çalışıyor. Diğer cevaplar tüm bunlara çarpıyordu.

Temel öneri, numaralandırmaların miras alınamayacağıdır - ancak sınıflar olabilir. Yani...

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

Sonra, başka bir üst düzey projede numaralarını devralmak için ...

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

Bunun üç gerçek avantajı var ...

  1. Numaralandırma tanımları her iki projede de otomatik olarak aynıdır - tanım gereği.
  2. Numaralandırma tanımlarında yapılan herhangi bir değişiklik, ikinci sınıfta herhangi bir değişiklik yapmak zorunda kalmadan otomatik olarak ikincisinde yankılanır.
  3. Numaralandırmalar aynı koda dayanır - böylece değerler kolayca (bazı uyarılarla) karşılaştırılabilir.

Çeteleler başvurmak için ilk proje , sınıfın öneki kullanabilirsiniz: BaseEnums.StatusType.Pending veya eklenti bir "statik BaseEnums kullanarak;"ifadelerini kullanın.

Gelen ikinci proje ancak kalıtsal sınıf ile uğraşan, ben alamadım "statik kullanarak ..." "miras çeteleler" yapılan tüm başvurular sınıfın öneki olacağını, böylece işe yaklaşımı, örneğin SubEnums.StatusType.Pending . Herkes "statik kullanarak" izin vermek için bir yol bulursa ikinci projede yaklaşımının , bana bildirin.

Bunu daha da iyi hale getirmek için ayarlanabileceğinden eminim - ama bu gerçekten işe yarıyor ve bu yaklaşımı çalışma projelerinde kullandım.

Yararlı bulursanız lütfen bunu yukarı oylayın.


2

Ayrıca aşırı yük numaralamalar istedim ve bir karışımını yarattığı bu sayfadaki 'Seven' cevabını ve bu kopyası yayında 'Merlyn Morgan-Graham' cevabını artı iyileştirmeler bir çift.
Çözümümün diğerlerine göre ana avantajları:

  • temel int değerinin otomatik artışı
  • otomatik adlandırma

Bu, kullanıma hazır bir çözümdür ve doğrudan projenize eklenebilir. Benim ihtiyaçları için tasarlanmış, bu yüzden bazı bölümlerini sevmiyorsanız, sadece kendi kodunuzla değiştirin.

İlk olarak, CEnumtüm özel numaraların devralması gereken temel sınıf vardır. .Net Enumtürüne benzer temel işlevlere sahiptir :

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

İkincisi, işte 2 türetilmiş Enum sınıfı. Tüm türetilmiş sınıfların beklendiği gibi çalışması için bazı temel yöntemlere ihtiyacı vardır. Her zaman aynı kazan plakası kodu; Henüz bunu temel sınıfa dış kaynak kullanmanın bir yolunu bulamadım. İlk miras seviyesinin kodu sonraki tüm seviyelerden biraz farklıdır.

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

Sınıflar aşağıdaki kodla başarıyla test edilmiştir:

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

Numaralandırmalar, benzeseler bile, gerçek sınıflar değildir. Dahili olarak, altta yatan tipleri gibi davranılırlar (varsayılan olarak Int32). Bu nedenle, bunu yalnızca bir sayımdan diğerine "kopyalayarak" ve eşitlik için karşılaştırmak üzere tamsayı numaralarına çevirerek yapabilirsiniz.


1

Numaralandırmalar diğer numaralandırmalardan kurtarılamaz, yalnızca int, uint, kısa, ushort, uzun, ulong, bayt ve sbyte'den kurtarılabilir.

Pascal'ın dediği gibi, bir enum değerini başlatmak için diğer numaraların değerlerini veya sabitlerini kullanabilirsiniz, ancak hepsi bu.


8
C # sözdizimi nedeniyle bir yanlış adlandırma biraz ama enum aslında int, uint, vb miras olamaz ... Kaputun altında hala System.Enum miras. Sadece enum temsil eden üye int, uint, vb yazılır ...
JaredPar

@JaredPar. Bir enum bir uint'ten çıkarıldığında, değerlerin tümü uint, vb. Anlamına gelir. Varsayılan olarak bir enum int. (C # belirtimine bir göz atın, enum SomeEnum: uint {...} gerçekten işe yarıyor.)
Jeroen Landheer

4
Aslında hayır. System.enum'u devralır. Daha önce ve daha sık burada yayınlandığı gibi, miras olduğunu düşündüğünüz sadece csharp bir dil dusambiguity olduğunu.
TomTom

1

başka bir olası çözüm:

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


1

Bu mümkün değildir (@JaredPar'dan daha önce bahsedildiği gibi). Bu sorunu çözmek için mantık koymaya çalışmak kötü bir uygulamadır. Eğer sahip olduğunuz bir base classşey varsa enum, tüm olasıları listelemelisiniz.enum-values orada ve sınıfın uygulanması o bilir değerlerle çalışmalıdır.

Örneğin, bir temel sınıfınız varsa BaseCatalogve bunun bir enum ProductFormats( Digital, Physical) var. O zaman hem ve hem de ürünleri içeren bir MusicCatalogveya BookCatalogolabilir , Ama sınıf ise , sadece ürünler içermelidir .DigitalPhysicalClothingCatalogPhysical


1

Bu partiye biraz geç kaldığımı anlıyorum, ama işte iki sentim.

Enum kalıtımının çerçeve tarafından desteklenmediği hepimiz açıktır. Bu konuda bazı çok ilginç çözümler önerildi, ancak hiçbiri aradığım şey gibi hissetmedi, bu yüzden kendim bir gitmek vardı.

Giriş: ObjectEnum

Kodu ve belgeleri buradan kontrol edebilirsiniz: https://github.com/dimi3tron/ObjectEnum .

Ve buradaki paket: https://www.nuget.org/packages/ObjectEnum

Veya sadece yükleyin: Install-Package ObjectEnum

Kısacası, ObjectEnum<TEnum>herhangi bir numaralandırma için bir sarıcı görevi görür. Alt sınıflarda GetDefinedValues ​​() yöntemini geçersiz kılarak, bu belirli sınıf için hangi numaralandırma değerlerinin geçerli olduğu belirtilebilir.

ObjectEnum<TEnum>Tanımlı değer kısıtlamalarını göz önünde bulundurarak, bir örneğin temeldeki enumun bir örneği gibi davranmasını sağlamak için bir dizi operatör aşırı yüklemesi eklenmiştir . Bu, örneği bir int veya enum değeriyle kolayca karşılaştırabileceğiniz ve böylece bir anahtar durumunda veya başka bir koşulda kullanabileceğiniz anlamına gelir.

Örnekler ve daha fazla bilgi için yukarıdaki github repo sözüne başvurmak istiyorum.

Umarım bunu faydalı bulursun. Daha fazla düşünce ve yorum yapmak için yorum yapmaktan veya github ile ilgili bir konuyu açmaktan çekinmeyin.

Aşağıda, neler yapabileceğinize ilişkin birkaç kısa örnek verilmiştir 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

Numaralandırmada kalıtım gerçekleştirebilirsiniz, ancak yalnızca aşağıdaki türlerle sınırlıdır. int, uint, bayt, sbyte, kısa, kısa, uzun, uzun

Örneğin

public enum Car:int{
Toyota,
Benz,
}

2
Ben OP sadece bir üs sayısal türünden, diğerinden bir enum devralmasına soruyordu düşünüyorum (tüm çeteleler dolaylı ya da dolaysız, C # yapın.)
reirab
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.