Quyền thừa kế Enum


391

Tôi có một enum trong một không gian tên cấp thấp. Tôi muốn cung cấp một lớp hoặc enum trong một không gian tên trung cấp "kế thừa" enum cấp thấp.

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

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

Tôi hy vọng rằng điều này là có thể, hoặc có lẽ một loại lớp nào đó có thể thay thế enum tiêu thụ sẽ cung cấp một lớp trừu tượng cho enum, nhưng vẫn để một thể hiện của lớp đó truy cập enum.

Suy nghĩ?

EDIT: Một trong những lý do tôi chưa chuyển đổi nó thành consts trong các lớp là vì enum cấp thấp là cần thiết cho một dịch vụ mà tôi phải tiêu thụ. Tôi đã được đưa ra các WSDL và XSD, định nghĩa cấu trúc này là một enum. Dịch vụ không thể thay đổi.


Câu trả lời:


462

Điều này là không thể. Enums không thể kế thừa từ các enums khác. Trong thực tế tất cả các enums phải thực sự thừa kế từ System.Enum. C # cho phép cú pháp thay đổi biểu diễn cơ bản của các giá trị enum trông giống như thừa kế, nhưng thực tế chúng vẫn kế thừa từ System.enum.

Xem phần 8.5.2 của thông số CLI để biết chi tiết đầy đủ. Thông tin liên quan từ thông số kỹ thuật

  • Tất cả các enum phải xuất phát từ System.Enum
  • Bởi vì ở trên, tất cả các enum là loại giá trị và do đó được niêm phong

2
Và tất cả các loại giá trị xuất phát từ System.ValueType
Raz Megrelidze 20/03/2016

4
Phải đề cập rằng câu trả lời của @Seven là một cách giải quyết hợp pháp: stackoverflow.com/a/4042826/538387
Tohid

nhưng câu trả lời của @ Steven không thể được sử dụng trong switchtình huống.
zionpi

@zionpi có nhưng lưu ý rằng (tôi tin) công tắc tiêu chuẩn được biên dịch thành cùng mã IL dưới dạng đầy đủ nếu, nếu không, khối khác sẽ: dù sao tôi nghĩ có cú pháp tốt hơn. Bạn mất khả năng chia sẻ lại / VS để tự động hoàn thành tất cả các báo cáo trường hợp, nhưng tôi nghĩ đó không phải là ngày tận thế. Đó là một sở thích cá nhân nhưng tôi không phải là người hâm mộ của tuyên bố chuyển đổi.
MemeDeveloper

165

Bạn có thể đạt được những gì bạn muốn với các lớp học:

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

Bây giờ bạn có thể sử dụng các lớp này tương tự như khi chúng là enum:

int i = Consume.B;

Cập nhật (sau khi cập nhật câu hỏi của bạn):

Nếu bạn gán cùng một giá trị int cho các hằng số như được định nghĩa trong enum hiện có, thì bạn có thể chuyển giữa enum và hằng số, ví dụ:

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
Làm thế nào để bạn liệt kê các lĩnh vực trong lớp này sau đó? Đối với tôi đó là hành vi quan trọng của một enum:Enum.GetValues(typeof(MyEnum)
Mike de Klerk

1
Bạn có thể sử dụng sự phản chiếu: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
mnieto

2
Bạn cần đảm bảo rằng việc thu thập các thuộc tính với sự phản chiếu bỏ qua các thuộc tính Đối tượng được kế thừa.
Robert

Phản xạ là siêu xấu cho nhiệm vụ đó.
dylanh724

1
Không cần sử dụng Reflection, việc triển khai tại codeproject.com/Articles/20805/EnhANCE-C-Enums là một cách tốt để làm điều đó, vì các đối tượng đang được tạo, chúng được thêm vào danh sách và danh sách đó có thể được sử dụng để trả về một danh sách các loại đối tượng Khi bạn trộn nó với sự kế thừa, bạn sẽ phải đảm bảo rằng bạn đang sử dụng đúng danh sách cho các lớp kế thừa.
PBo

112

Câu trả lời ngắn gọn là không. Bạn có thể chơi một chút, nếu bạn muốn:

Bạn luôn có thể làm một cái gì đó như thế này:

private enum Base
{
    A,
    B,
    C
}

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

Nhưng, nó không hoạt động tốt lắm vì Base.A! = Consume.A

Bạn luôn có thể làm một cái gì đó như thế này, mặc dù:

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

Để giao thoa giữa Base và Consume ...

Bạn cũng có thể sử dụng các giá trị của enum dưới dạng ints và so sánh chúng là ints thay vì enum, nhưng kiểu đó cũng rất tệ.

Trả về phương thức mở rộng nên gõ cast kiểu T.


4
Tôi đào cái này, anh bạn. Đã sử dụng khái niệm này để đánh bóng một số enum từ ORM của tôi sang giao diện công cộng của tôi (đến những người không có tham chiếu ORM).
ObjectType

5
Người ta có thể bỏ enum để so sánh với công việc:Base.A == (Base)Consume.A
Kresimir

1
Sử dụng (thập phân) Base.A == (thập phân) Tiêu thụ.A. Lý do: Đây là cách bit cờ / mặt nạ kết hợp hoạt động (ví dụ: trong Enum.IsDefined msdn.microsoft.com/en-us/l Library / trộm ). Vì vậy, một enum có thể được đặt thành một số nguyên không được xác định trong enum. Kiểm tra tiêu thụ = 123456;
TamusJRoyce

3
@TamusJRoyce thập phân? intsẽ có ý nghĩa hơn rất nhiều. Khi nào một enum có một phần phân đoạn!?!?!
ErikE

Ít nhất, điều này đảm bảo rằng các hằng số enum tương ứng có cùng giá trị nguyên. Xét cho cùng, enums chỉ là một tập hợp các hằng số nguyên. C # không thực thi rằng các giá trị được gán là hằng số vaild enum, tức là enum không phải là loại an toàn theo nghĩa nghiêm ngặt.
Olivier Jacot-Descombes

98

Các giải pháp trên sử dụng các lớp với hằng số int thiếu loại an toàn. Tức là bạn có thể phát minh ra các giá trị mới thực sự không được xác định trong lớp. Hơn nữa, ví dụ không thể viết một phương thức lấy một trong các lớp này làm đầu vào.

Bạn sẽ cần phải viết

public void DoSomethingMeaningFull(int consumeValue) ...

Tuy nhiên, có một giải pháp dựa trên lớp của những ngày xưa của Java, khi không có enum có sẵn. Điều này cung cấp một hành vi gần như enum. Nhắc nhở duy nhất là các hằng số này không thể được sử dụng trong câu lệnh 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
Tôi nghĩ rằng đây là câu trả lời đúng. Bạn không thể có quyền thừa kế cho Enum nhưng điều này có thể cho phép bạn quản lý nó!
robob

11
Đẹp và sạch sẽ. +1. Chỉ cần một gợi ý, bạn thực sự không cần giá trị int.
Ignacio Soler Garcia

1
Tôi chưa bao giờ nghĩ về việc liệt kê như thể bạn có thể nói FileOpenMode.Read> FileOpenMode.Write. Nếu đó là trường hợp thì bạn cần một int hoặc thậm chí tốt hơn một IEqualityComparer cho enum đó. Trân trọng.
Ignacio Soler Garcia

3
@binki sử dụng ngẫu nhiên objectsẽ làm cho các giá trị khác nhau cho mỗi lần khởi tạo lắp ráp để chúng không thể được nối tiếp.
ivan_pozdeev

2
Nhưng điều này không cho phép bạn "chuyển đổi" trên MyEnum, phải không? Ý tôi là đó chủ yếu là lý do tại sao tôi sử dụng enums ...
MemphiZ

13

Bỏ qua thực tế rằng cơ sở là một từ dành riêng, bạn không thể thừa kế enum.

Điều tốt nhất bạn có thể làm là một cái gì đó như thế:

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

Vì tất cả chúng đều cùng một loại cơ sở (ví dụ: int), bạn có thể gán giá trị từ một thể hiện của một loại cho loại khác. Không lý tưởng nhưng nó hoạt động.


2
cơ sở được bảo lưu nhưng Base không
erikkallen

2
Anh ấy đề cập đến việc OP sử dụng căn cứ làm tên enum, đó chỉ là một tên ví dụ mà tôi chắc chắn
John Rasch

Giống như câu trả lời của Genisio.
nawfal

6

Tôi biết câu trả lời này hơi muộn nhưng đây là điều tôi đã là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        
}

Sau đó, tôi có thể làm những việc như:

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
Số ma thuật có thể được thay thế bằng các đối tượng theo stackoverflow.com/questions/757684/ cấp . Nhưng đối với trường hợp cụ thể này, bạn có thể tận dụng tốt nhất cả hai thế giới bằng cách sử dụng các tính năng của danh pháp sinh học hiện có để đảm bảo tính duy nhất.
ivan_pozdeev

4

Đây là những gì tôi đã làm. Những gì tôi đã làm khác nhau là sử dụng cùng một tên và newtừ khóa trên "tiêu thụ" enum. Vì tên của enumgiống nhau, bạn có thể sử dụng nó một cách vô thức và nó sẽ đúng. Thêm vào đó bạn nhận được intellisense. Bạn chỉ cần cẩn thận khi thiết lập rằng các giá trị được sao chép từ cơ sở và giữ cho chúng được đồng bộ hóa. Bạn có thể giúp điều đó cùng với các bình luận mã. Đây là một lý do khác tại sao trong cơ sở dữ liệu khi lưu trữ enumcác giá trị tôi luôn lưu trữ chuỗi chứ không phải giá trị. Bởi vì nếu bạn đang sử dụng các giá trị nguyên tăng tự động được gán, chúng có thể thay đổi theo thời gian.

// 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
Xem xét việc đặt phạm vi khác cho các giá trị mới trong lớp dẫn xuất (ví dụ SmallMedium = 100,), để bạn có thể giữ khả năng tương thích với các phiên bản cũ hơn của phần mềm khi bạn thêm các giá trị mới vào lớp cơ sở. Ví dụ, việc thêm một Hugekích thước trong enum cơ sở của bạn sẽ gán 4cho giá trị của nó, nhưng 4đã được thực hiện SmallMediumtrong lớp dẫn xuất.
Roberto

1
@Roberto, Để giải quyết vấn đề này, tôi không bao giờ duy trì các giá trị enum, mà chỉ các tên. Và giữ cho chúng được đồng bộ hóa là một yêu cầu ở đây. Vì vậy, việc thêm Hugevào lớp cơ sở sẽ cần một Hugelớp con trướcSmallMedium
chập chững vào

2
BaseBallcó thể không phải là tên thông minh nhất ở đây. Thật khó hiểu. Vì một quả bóng chày thực sự là một thứ. Nếu bạn bỏ lỡ rằng đây chỉ là một lớp cơ bản cho bóng, có vẻ rất kỳ lạ khi một quả bóng chuyền được thừa hưởng từ một quả bóng chày nhỏ hơn vật lý :). Đề nghị của tôi là chỉ sử dụngBall
Nick N.

3

Giải pháp thay thế

Trong công ty của tôi, chúng tôi tránh "nhảy qua các dự án" để đến các dự án cấp thấp hơn không phổ biến. Chẳng hạn, lớp trình bày / API của chúng tôi chỉ có thể tham chiếu lớp miền của chúng tôi và lớp miền chỉ có thể tham chiếu lớp dữ liệu.

Tuy nhiên, đây là một vấn đề khi có những enum cần được tham chiếu bởi cả lớp trình bày và lớp miền.

Đây là giải pháp mà chúng tôi đã thực hiện (cho đến nay). Đó là một giải pháp khá tốt và hoạt động tốt cho chúng tôi. Các câu trả lời khác đã được nhấn xung quanh này.

Tiền đề cơ bản là enums không thể được kế thừa - nhưng các lớp có thể. Vì thế...

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

Sau đó, để "kế thừa" các enum trong một dự án cấp cao khác ...

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

Điều này có ba lợi thế thực sự ...

  1. Các định nghĩa enum tự động giống nhau trong cả hai dự án - theo định nghĩa.
  2. Mọi thay đổi đối với các định nghĩa enum sẽ tự động lặp lại trong lần thứ hai mà không phải thực hiện bất kỳ sửa đổi nào đối với lớp thứ hai.
  3. Các enum dựa trên cùng một mã - vì vậy các giá trị có thể dễ dàng được so sánh (với một số cảnh báo).

Để tham chiếu các enum trong dự án đầu tiên , bạn có thể sử dụng tiền tố của lớp: BaseEnums.StatusType.Pending hoặc thêm một "bằng cách sử dụng BaseEnums tĩnh;" tuyên bố cho việc sử dụng của bạn.

Tuy nhiên, trong dự án thứ hai khi xử lý lớp kế thừa, tôi không thể sử dụng cách tiếp cận "sử dụng tĩnh ..." , vì vậy tất cả các tham chiếu đến " enum kế thừa" sẽ được thêm tiền tố vào lớp, ví dụ SubEnums.StatusType.Pending . Nếu bất cứ ai nghĩ ra cách cho phép sử dụng phương pháp "sử dụng tĩnh" trong dự án thứ hai, hãy cho tôi biết.

Tôi chắc chắn rằng điều này có thể được điều chỉnh để làm cho nó thậm chí còn tốt hơn - nhưng điều này thực sự hoạt động và tôi đã sử dụng phương pháp này trong các dự án làm việc.

Vui lòng bỏ phiếu này nếu bạn thấy nó hữu ích.


2

Tôi cũng muốn làm quá tải Enums và tạo ra một hỗn hợp câu trả lời của 'Seven' trên trang nàycâu trả lời của 'Merlyn Morgan-Graham' trên một bài đăng trùng lặp về điều này , cùng với một vài cải tiến.
Ưu điểm chính của giải pháp của tôi so với các giải pháp khác:

  • tự động tăng giá trị int bên dưới
  • đặt tên tự động

Đây là một giải pháp vượt trội và có thể được chèn trực tiếp vào dự án của bạn. Nó được thiết kế theo nhu cầu của tôi, vì vậy nếu bạn không thích một số phần của nó, chỉ cần thay thế chúng bằng mã của riêng bạn.

Đầu tiên, có lớp cơ sở CEnummà tất cả các enum tùy chỉnh nên kế thừa từ đó. Nó có chức năng cơ bản, tương tự như Enumloại .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;
    }
  }
}

Thứ hai, đây là 2 lớp Enum có nguồn gốc. Tất cả các lớp dẫn xuất cần một số phương thức cơ bản để làm việc như mong đợi. Nó luôn luôn là cùng một mã soạn sẵn; Tôi chưa tìm được cách nào để thuê ngoài nó cho lớp cơ sở. Mã của cấp kế thừa đầu tiên hơi khác so với tất cả các cấp tiếp theo.

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

Các lớp đã được kiểm tra thành công với mã 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
}

1

Enums không phải là các lớp thực tế, ngay cả khi chúng trông giống như nó. Trong nội bộ, chúng được đối xử giống như loại cơ bản của chúng (theo mặc định Int32). Do đó, bạn chỉ có thể thực hiện việc này bằng cách "sao chép" các giá trị đơn từ enum này sang enum khác và chuyển chúng thành số nguyên của chúng để so sánh chúng với đẳng thức.


1

Enums không thể được lấy từ các enums khác, mà chỉ từ int, uint, short, ushort, long, ulong, byte và sbyte.

Giống như Pascal đã nói, bạn có thể sử dụng các giá trị hoặc hằng số của enum khác để khởi tạo một giá trị enum, nhưng đó là về nó.


8
Đó là một chút sai lầm vì cú pháp c # nhưng enum thực sự không thể kế thừa từ int, uint, v.v ... Dưới mui xe họ vẫn thừa hưởng từ System.Enum. Chỉ là thành viên đại diện cho enum được gõ vào int, uint, v.v ...
JaredPar

@JaredPar. Khi một enum được lấy từ một uint, điều đó có nghĩa là các giá trị của nó đều là uint, v.v. Theo mặc định, một enum thừa hưởng int. (Hãy xem thông số kỹ thuật của C #, enum someEnum: uint {...} thực sự hoạt động.)
Jeroen Landheer

4
Thật ra là không. Nó kế thừa System.enum. Như đã được đăng trước đây và thường xuyên hơn ở đây, những gì bạn nghĩ là thừa kế chỉ là một ngôn ngữ khó hiểu trong csharp.
TomTom

1

một giải pháp khả thi khác:

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

Điều này là không thể (như @JaredPar đã đề cập). Cố gắng đưa logic để giải quyết vấn đề này là một thực tế tồi. Trong trường hợp bạn có một base classcái có enum, bạn nên liệt kê tất cả những gì có thể enum-valuesở đó và việc triển khai lớp sẽ hoạt động với các giá trị mà nó biết.

Ví dụ: Giả sử bạn có một lớp cơ sở BaseCatalogvà nó có enum ProductFormats( Digital, Physical). Sau đó, bạn có thể có một MusicCataloghoặc BookCatalogcó thể chứa cả hai DigitalPhysicalsản phẩm, nhưng nếu là lớp ClothingCatalog, nó chỉ nên chứa Physicalsản phẩm.


1

Tôi nhận ra mình đến bữa tiệc này hơi muộn, nhưng đây là hai xu của tôi.

Tất cả chúng ta đều rõ ràng rằng kế thừa Enum không được khung hỗ trợ. Một số cách giải quyết rất thú vị đã được đề xuất trong chủ đề này, nhưng không ai trong số họ cảm thấy khá giống với những gì tôi đang tìm kiếm, vì vậy tôi đã tự mình đi tìm nó.

Giới thiệu: ObjectEnum

Bạn có thể kiểm tra mã và tài liệu ở đây: https://github.com/dimi3tron/ObjectEnum .

Và gói ở đây: https://www.nuget.org/packages/ObjectEnum

Hoặc chỉ cần cài đặt nó: Install-Package ObjectEnum

Nói tóm lại, ObjectEnum<TEnum>hoạt động như một bọc cho bất kỳ enum. Bằng cách ghi đè GetDefinedValues ​​() trong các lớp con, người ta có thể chỉ định giá trị enum nào là hợp lệ cho lớp cụ thể này.

Một số quá tải toán tử đã được thêm vào để làm cho một ObjectEnum<TEnum>cá thể hoạt động như thể nó là một thể hiện của enum bên dưới, ghi nhớ các hạn chế giá trị được xác định. Điều này có nghĩa là bạn có thể dễ dàng so sánh thể hiện với giá trị int hoặc enum và do đó sử dụng nó trong trường hợp chuyển đổi hoặc bất kỳ điều kiện nào khác.

Tôi muốn tham khảo repo github đề cập ở trên để biết ví dụ và thông tin thêm.

Tôi hy vọng bạn thấy nó hữu dụng. Hãy bình luận hoặc mở một vấn đề trên github để có thêm suy nghĩ hoặc bình luận.

Dưới đây là một vài ví dụ ngắn về những gì bạn có thể làm với 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

Bạn có thể thực hiện kế thừa trong enum, tuy nhiên, nó chỉ giới hạn ở các loại sau. int, uint, byte, sbyte, ngắn, ushort, dài, ulong

Ví dụ

public enum Car:int{
Toyota,
Benz,
}

2
Tôi nghĩ rằng OP đã yêu cầu kế thừa một enum từ một loại khác, không chỉ từ một kiểu số cơ bản (mà tất cả các enum làm trong C #, mặc nhiên hoặc rõ ràng.)
thiệu lại vào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.