C # vs Java Enum (đối với những người mới sử dụng C #)


182

Tôi đã lập trình bằng Java được một thời gian và vừa bị ném vào một dự án được viết hoàn toàn bằng C #. Tôi đang cố gắng tăng tốc độ trong C # và nhận thấy các enum được sử dụng ở một số nơi trong dự án mới của tôi, nhưng thoạt nhìn, các enum của C # có vẻ đơn giản hơn so với triển khai Java 1.5+. Bất cứ ai cũng có thể liệt kê sự khác biệt giữa các liệt kê C # và Java và cách khắc phục sự khác biệt? (Tôi không muốn bắt đầu một cuộc chiến ngọn lửa ngôn ngữ. Tôi chỉ muốn biết cách thực hiện một số điều trong C # mà tôi đã từng làm trong Java). Ví dụ: ai đó có thể đăng một bản sao C # lên ví dụ về hành tinh nổi tiếng của Sun không?

public enum Planet {
  MERCURY (3.303e+23, 2.4397e6),
  VENUS   (4.869e+24, 6.0518e6),
  EARTH   (5.976e+24, 6.37814e6),
  MARS    (6.421e+23, 3.3972e6),
  JUPITER (1.9e+27,   7.1492e7),
  SATURN  (5.688e+26, 6.0268e7),
  URANUS  (8.686e+25, 2.5559e7),
  NEPTUNE (1.024e+26, 2.4746e7),
  PLUTO   (1.27e+22,  1.137e6);

  private final double mass;   // in kilograms
  private final double radius; // in meters
  Planet(double mass, double radius) {
      this.mass = mass;
      this.radius = radius;
  }
  public double mass()   { return mass; }
  public double radius() { return radius; }

  // universal gravitational constant  (m3 kg-1 s-2)
  public static final double G = 6.67300E-11;

  public double surfaceGravity() {
      return G * mass / (radius * radius);
  }
  public double surfaceWeight(double otherMass) {
      return otherMass * surfaceGravity();
  }
}

// Example usage (slight modification of Sun's example):
public static void main(String[] args) {
    Planet pEarth = Planet.EARTH;
    double earthRadius = pEarth.radius(); // Just threw it in to show usage

    // Argument passed in is earth Weight.  Calculate weight on each planet:
    double earthWeight = Double.parseDouble(args[0]);
    double mass = earthWeight/pEarth.surfaceGravity();
    for (Planet p : Planet.values())
       System.out.printf("Your weight on %s is %f%n",
                         p, p.surfaceWeight(mass));
}

// Example output:
$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
[etc ...]

1
@ycomp Tôi không thể lấy tín dụng cho việc đó. Nó đến từ Sun (nay là Oracle): docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Ogre Psalm33

Câu trả lời:


210

Các liệt kê trong CLR được đặt tên đơn giản là hằng số. Các loại cơ bản phải là tích phân. Trong Java, một phép liệt kê giống như một thể hiện được đặt tên của một kiểu. Loại đó có thể khá phức tạp và - như ví dụ của bạn cho thấy - chứa nhiều trường thuộc nhiều loại khác nhau.

Để chuyển ví dụ sang C #, tôi chỉ cần thay đổi enum thành một lớp không thay đổi và hiển thị các thể hiện chỉ đọc tĩnh của lớp đó:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Planet planetEarth = Planet.MERCURY;

            double earthRadius = pEarth.Radius; // Just threw it in to show usage
            double earthWeight = double.Parse("123");
            double earthMass   = earthWeight / pEarth.SurfaceGravity();

            foreach (Planet p in Planet.Values)
                Console.WriteLine($"Your weight on {p} is {p.SurfaceWeight(mass)}");

            Console.ReadKey();
        }
    }

    public class Planet
    {
        public static readonly Planet MERCURY = new Planet("Mercury", 3.303e+23, 2.4397e6);
        public static readonly Planet VENUS   = new Planet("Venus", 4.869e+24, 6.0518e6);
        public static readonly Planet EARTH   = new Planet("Earth", 5.976e+24, 6.37814e6);
        public static readonly Planet MARS    = new Planet("Mars", 6.421e+23, 3.3972e6);
        public static readonly Planet JUPITER = new Planet("Jupiter", 1.9e+27, 7.1492e7);
        public static readonly Planet SATURN  = new Planet("Saturn", 5.688e+26, 6.0268e7);
        public static readonly Planet URANUS  = new Planet("Uranus", 8.686e+25, 2.5559e7);
        public static readonly Planet NEPTUNE = new Planet("Neptune", 1.024e+26, 2.4746e7);
        public static readonly Planet PLUTO   = new Planet("Pluto", 1.27e+22, 1.137e6);

        public static IEnumerable<Planet> Values
        {
            get
            {
                yield return MERCURY;
                yield return VENUS;
                yield return EARTH;
                yield return MARS;
                yield return JUPITER;
                yield return SATURN;
                yield return URANUS;
                yield return NEPTUNE;
                yield return PLUTO;
            }
        }

        public string Name   { get; private set; }
        public double Mass   { get; private set; }
        public double Radius { get; private set; }

        Planet(string name, double mass, double radius) => 
            (Name, Mass, Radius) = (name, mass, radius);

        // Wniversal gravitational constant  (m3 kg-1 s-2)
        public const double G = 6.67300E-11;
        public double SurfaceGravity()            => G * mass / (radius * radius);
        public double SurfaceWeight(double other) => other * SurfaceGravity();
        public override string ToString()         => name;
    }
}

4
Đây là loại enum an toàn loại mà người nghèo chúng ta buộc phải sử dụng Java 1.4 trở xuống phải thực hiện ... enum của Java 5 có lẽ là tính năng tốt nhất của Java 5+, đặc biệt là vì chúng có thể được sử dụng trong các câu lệnh chuyển đổi.
MetroidFan2002

9
@Chris: chỉ có enum cờ nên được số nhiều. Đó là, liệt kê các thành viên được kết hợp bằng cách sử dụng | nhà điều hành.
Kent Boogaart

5
@Mladen: Nó phụ thuộc hoàn toàn vào bối cảnh. Một bảng liệt kê các hành tinh có thể hoàn toàn phù hợp với một trò chơi cung cấp quyền truy cập vào một số hành tinh giới hạn. Thay đổi mã có thể chính xác là những gì bạn muốn nếu một hành tinh mới được thêm vào trò chơi.
Kent Boogaart

3
@Richie_W bạn có thể lặp lại các enum bằng thuộc tính Values.
Jonathan

23
Wow ... Thật không thể tin được khi thấy một cái gì đó được triển khai theo cách thức dài dòng hơn trong C # so với trong Java
Sune Rasmussen

218

Trong C #, bạn có thể xác định các phương thức mở rộng trên enums và điều này bù cho một số chức năng còn thiếu.

Bạn có thể định nghĩa Planetlà một enum và cũng có các phương thức mở rộng tương đương surfaceGravity()surfaceWeight().

Tôi đã sử dụng các thuộc tính tùy chỉnh theo đề xuất của Mikhail , nhưng điều tương tự có thể đạt được bằng cách sử dụng Từ điển.

using System;
using System.Reflection;

class PlanetAttr: Attribute
{
    internal PlanetAttr(double mass, double radius)
    {
        this.Mass = mass;
        this.Radius = radius;
    }
    public double Mass { get; private set; }
    public double Radius { get; private set; }
}

public static class Planets
{
    public static double GetSurfaceGravity(this Planet p)
    {
        PlanetAttr attr = GetAttr(p);
        return G * attr.Mass / (attr.Radius * attr.Radius);
    }

    public static double GetSurfaceWeight(this Planet p, double otherMass)
    {
        return otherMass * p.GetSurfaceGravity();
    }

    public const double G = 6.67300E-11;

    private static PlanetAttr GetAttr(Planet p)
    {
        return (PlanetAttr)Attribute.GetCustomAttribute(ForValue(p), typeof(PlanetAttr));
    }

    private static MemberInfo ForValue(Planet p)
    {
        return typeof(Planet).GetField(Enum.GetName(typeof(Planet), p));
    }

}

public enum Planet
{
    [PlanetAttr(3.303e+23, 2.4397e6)]  MERCURY,
    [PlanetAttr(4.869e+24, 6.0518e6)]  VENUS,
    [PlanetAttr(5.976e+24, 6.37814e6)] EARTH,
    [PlanetAttr(6.421e+23, 3.3972e6)]  MARS,
    [PlanetAttr(1.9e+27,   7.1492e7)]  JUPITER,
    [PlanetAttr(5.688e+26, 6.0268e7)]  SATURN,
    [PlanetAttr(8.686e+25, 2.5559e7)]  URANUS,
    [PlanetAttr(1.024e+26, 2.4746e7)]  NEPTUNE,
    [PlanetAttr(1.27e+22,  1.137e6)]   PLUTO
}

20
Tôi nghĩ rằng điều này nên được bình chọn nhiều hơn. Nó gần hơn với cách thức hoạt động của Java. Tôi có thể làm một cái gì đó như Planet.MERCURY.GetSurfaceGravity () <- Lưu ý phương thức mở rộng trên Enum!
thenonhacker

2
Chắc chắn là có. Các phương thức mở rộng trên Enums (heck, phương thức mở rộng nói chung) là một bổ sung tuyệt vời cho C #.
KeithS

3
@ ALLonGuralnek Cảm ơn. Không phải tất cả mọi người sẽ đồng ý về siêu dữ liệu mặc dù. Xem bình luận của MattDavey về một câu hỏi liên quan đến codereview.stackexchange .
vây

@finnw: Tôi chưa bao giờ nghe nói về trang web Code Review SE - cảm ơn vì điều đó! Tôi đã tiếp tục cuộc thảo luận này ở đó (mặc dù nó có thể xứng đáng với câu hỏi của riêng mình ở đây về Lập trình viên).
Allon Guralnek

Đây là một giải pháp tuyệt vời - có ai đã thử nghiệm hiệu suất của việc này chưa? ví dụ: tôi mất bao lâu để truy cập thuộc tính, so với việc truy cập một thuộc tính của một lớp.
Simon Meyer

35

Trong thuộc tính C # có thể được sử dụng với enums. Ví dụ hay về mẫu lập trình này với mô tả chi tiết có ở đây (Codeproject)

public enum Planet
{
   [PlanetAttr(3.303e+23, 2.4397e6)]
   Mercury,
   [PlanetAttr(4.869e+24, 6.0518e6)]
   Venus
} 

Chỉnh sửa: câu hỏi này gần đây đã được hỏi lại và được trả lời bởi Jon Skeet: Điều gì tương đương với enum của Java trong C #? Các lớp bên trong riêng trong C # - tại sao chúng không được sử dụng thường xuyên hơn?

Chỉnh sửa 2: xem câu trả lời được chấp nhận mở rộng cách tiếp cận này một cách rất xuất sắc!


1
Đẹp! Điều này chỉ cảm thấy hơi cồng kềnh, nhưng nếu không thì là một phương pháp rất được chấp nhận để thêm dữ liệu vào một enum. Tôi thực sự ngạc nhiên rằng phải mất một thời gian dài để đề cập đến giải pháp tuyệt vời này!
Ogre Psalm33

13

Các enum Java thực sự là các lớp đầy đủ có thể có một hàm tạo và các phương thức riêng, v.v., trong khi các enum C # chỉ là các số nguyên được đặt tên. Việc triển khai Java của IMO vượt trội hơn nhiều.

Trang này sẽ giúp bạn rất nhiều trong khi học c # đến từ một trại java. (Liên kết chỉ ra sự khác biệt về enums (cuộn lên / xuống cho những thứ khác)


1
Mặc dù liên kết của bạn cung cấp một cái nhìn tổng quan thú vị, bao quát về sự tương đồng và khác biệt giữa C # và Java, có rất nhiều lỗi trong văn bản (ví dụ: nói sai rằng Java được bảo vệ bằng C # bên trong trong khi nó phải được bảo vệ bên trong). Vì vậy, đừng coi mọi thứ ở đó là hiển nhiên :)
mafu

1
Tôi sẽ không nói các enum Java là vượt trội ngay cả khi tôi là một fan hâm mộ của java. C # hỗ trợ khai báo số nguyên dễ dàng như FOO = 0dễ sử dụng hơn trong các công cụ ORM (không ordinal()cần sử dụng dễ bị lỗi ). Hơn nữa C # hỗ trợ các bảng liệt kê bit thường rất hữu ích, đặc biệt là kết hợp với EntityFramework. Java nên mở rộng các enum của chúng để cho phép chúng được liên kết với các số nguyên. Sau đó, họ sẽ vượt trội :)
djmj

4

Một cái gì đó như thế này tôi nghĩ:

public class Planets 
{
    public static readonly Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
    public static readonly Planet VENUS = new Planet(4.869e+24, 6.0518e6);
    public static readonly Planet EARTH = new Planet(5.976e+24, 6.37814e6);
    public static readonly Planet MARS = new Planet(6.421e+23, 3.3972e6);
    public static readonly Planet JUPITER = new Planet(1.9e+27,   7.1492e7);
    public static readonly Planet SATURN = new Planet(5.688e+26, 6.0268e7);
    public static readonly Planet URANUS = new Planet(8.686e+25, 2.5559e7);
    public static readonly Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);
    public static readonly Planet PLUTO = new Planet(1.27e+22,  1.137e6);
}

public class Planet
{
    public double Mass {get;private set;}
    public double Radius {get;private set;}

    Planet(double mass, double radius)
    {
        Mass = mass;
        Radius = radius;
    }

    // universal gravitational constant  (m3 kg-1 s-2)
    private static readonly double G = 6.67300E-11;

    public double SurfaceGravity()
    {
        return G * Mass / (Radius * Radius);
    }

    public double SurfaceWeight(double otherMass)
    {
        return otherMass * SurfaceGravity();
    }
}

Hoặc kết hợp các hằng số vào Planetlớp như trên


8
Không hoàn toàn - nhà xây dựng Planet nên ở chế độ riêng tư; một phần của quan điểm là chúng là một tập hợp các giá trị cố định. Các giá trị sau đó cũng sẽ được định nghĩa trong lớp Planet.
Jon Skeet

Chưa. 1) điều tra viên bị thiếu :) 2) enum không bao giờ có thể thay đổi. Cuối cùng, mã của bạn xin một lớp duy nhất (đặc biệt khi bạn đang có một nhà xây dựng riêng)
nawfal

3

Đây là một ý tưởng thú vị khác phục vụ cho hành vi tùy chỉnh có sẵn trong Java. Tôi đã đưa ra Enumerationlớp cơ sở sau :

public abstract class Enumeration<T>
    where T : Enumeration<T>
{   
    protected static int nextOrdinal = 0;

    protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>();
    protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>();

    protected readonly string name;
    protected readonly int ordinal;

    protected Enumeration(string name)
        : this (name, nextOrdinal)
    {
    }

    protected Enumeration(string name, int ordinal)
    {
        this.name = name;
        this.ordinal = ordinal;
        nextOrdinal = ordinal + 1;
        byOrdinal.Add(ordinal, this);
        byName.Add(name, this);
    }

    public override string ToString()
    {
        return name;
    }

    public string Name 
    {
        get { return name; }
    }

    public static explicit operator int(Enumeration<T> obj)
    {
        return obj.ordinal;
    }

    public int Ordinal
    {
        get { return ordinal; }
    }
}

Về cơ bản, nó có một tham số kiểu để số đếm thứ tự sẽ hoạt động chính xác trên các bảng liệt kê khác nhau. OperatorVí dụ của Jon Skeet từ câu trả lời của anh ta cho một câu hỏi khác (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) ở trên sau đó trở thành:

public class Operator : Enumeration<Operator>
{
    public static readonly Operator Plus = new Operator("Plus", (x, y) => x + y);
    public static readonly Operator Minus =  new Operator("Minus", (x, y) => x - y);
    public static readonly Operator Times =  new Operator("Times", (x, y) => x * y);
    public static readonly Operator Divide = new Operator("Divide", (x, y) => x / y);

    private readonly Func<int, int, int> op;

    // Prevent other top-level types from instantiating
    private Operator(string name, Func<int, int, int> op)
        :base (name)
    {
        this.op = op;
    }

    public int Execute(int left, int right)
    {
        return op(left, right);
    }
}

Điều này mang lại một vài lợi thế.

  • Hỗ trợ thông thường
  • Chuyển đổi sang stringintlàm cho báo cáo chuyển đổi khả thi
  • GetType () sẽ cho cùng một kết quả cho từng giá trị của kiểu liệt kê dẫn xuất.
  • Các phương thức tĩnh từ System.Enumcó thể được thêm vào lớp Enumutions cơ sở để cho phép cùng chức năng.

3

chúng tôi vừa thực hiện một phần mở rộng enum cho c # https://github.com/simonmau/enum_ext

Đây chỉ là một triển khai cho các loại, nhưng nó hoạt động rất tốt vì vậy chúng tôi đã tạo một gói để chia sẻ - hãy vui vẻ với nó

public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
{
    public static readonly Weekday Monday = new Weekday(1, "--Monday--");
    public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
    public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
    ....

    private Weekday(int id, string name) : base(id, name)
    {
    }
}

2

Một enum Java là đường cú pháp để trình bày các liệt kê theo cách OO. Chúng là các lớp trừu tượng mở rộng lớp Enum trong Java và mỗi giá trị enum giống như một triển khai cá thể công khai cuối cùng tĩnh của lớp enum. Nhìn vào các lớp được tạo và để biết "Foo" với 10 giá trị, bạn sẽ thấy các lớp "Foo $ 1" thông qua các lớp "Foo $ 10" được tạo.

Mặc dù vậy, tôi không biết C #, tôi chỉ có thể suy đoán rằng một enum trong ngôn ngữ đó giống như một enum truyền thống trong các ngôn ngữ kiểu C. Tôi thấy từ một tìm kiếm nhanh của Google rằng họ có thể giữ nhiều giá trị, tuy nhiên, có lẽ chúng được triển khai theo cách tương tự, nhưng với nhiều hạn chế hơn nhiều so với những gì trình biên dịch Java cho phép.


3
Chà tất cả mọi thứ trong Java và C # đều là về cú pháp cú pháp cho mã byte JVM hoặc CLR? :) Chỉ cần nói '
thenonhacker

2

Các enum Java cho phép chuyển đổi an toàn kiểu dễ dàng từ tên bằng cách sử dụng phương thức valueOf do trình biên dịch tạo, tức là

// Java Enum has generics smarts and allows this
Planet p = Planet.valueOf("MERCURY");

Tương đương với một enum thô trong C # thì dài dòng hơn:

// C# enum - bit of hoop jumping required
Planet p = (Planet)Enum.Parse(typeof(Planet), "MERCURY");

Tuy nhiên, nếu bạn đi xuống tuyến đường được Kent sugegsted, bạn có thể dễ dàng thực hiện một ValueOfphương thức trong lớp enum của mình.


Ví dụ Java đang sử dụng một phương thức tổng hợp được tạo bởi trình biên dịch - không liên quan gì đến tổng quát. Enum có một phương thức valueOf chung, nhưng sử dụng chung chung của Class chứ không phải của Enum.
Tom Hawtin - tackline

2

Tôi nghi ngờ các enum trong C # chỉ là hằng số bên trong CLR, nhưng không quen thuộc với chúng. Tôi đã dịch ngược một số lớp trong Java và tôi có thể nói với bạn rằng Enums là một khi bạn chuyển đổi.

Java làm điều gì đó lén lút. Nó coi lớp enum là một lớp bình thường, gần như tôi có thể hình dung, sử dụng nhiều macro khi tham chiếu các giá trị enum. Nếu bạn có một câu lệnh tình huống trong một lớp Java sử dụng enum, nó sẽ thay thế các tham chiếu enum cho các số nguyên. Nếu bạn cần đi đến chuỗi, nó sẽ tạo ra một chuỗi các chuỗi được lập chỉ mục bởi một thứ tự mà nó sử dụng trong mỗi lớp. Tôi nghi ngờ để tiết kiệm quyền anh.

Nếu bạn tải xuống trình dịch ngược này, bạn sẽ thấy cách nó tạo ra lớp của nó một tích hợp nó. Khá hấp dẫn để thành thật. Tôi đã từng không sử dụng lớp enum bởi vì tôi nghĩ rằng nó chỉ là cồng kềnh cho một mảng các hằng số. Tôi thích nó hơn là cách giới hạn mà bạn có thể sử dụng chúng trong C #.

http://members.fortunecity.com/neshkov/dj.html - Trình dịch ngược Java


0

Enum trong Java phức tạp hơn nhiều so với C # enum và do đó mạnh hơn. Vì nó chỉ là một đường tổng hợp thời gian biên dịch khác, tôi tự hỏi liệu nó có thực sự đáng để đưa ngôn ngữ vào việc sử dụng hạn chế trong các ứng dụng thực tế hay không. Đôi khi, việc giữ ngôn ngữ ngoài ngôn ngữ khó hơn là tạo áp lực để đưa vào một tính năng nhỏ.


2
Tôi tôn trọng không đồng ý. Các enum Java 1.5 là một tính năng ngôn ngữ mạnh mẽ mà tôi đã sử dụng nhiều lần để triển khai một giải pháp OO trung tâm hơn cho một vấn đề liên quan đến tập hợp các mục có tên rời rạc.
Ogre Psalm33

1
Có thể là bạn đã làm. Nhưng ngoài khả năng tích hợp ngôn ngữ 'chuyển đổi' thông minh, phần còn lại của chức năng có thể dễ dàng được sao chép trong chính C # hoặc Java như các ví dụ trên cho thấy.
dmihailescu

@dmihailescu "Sau đó, enum trong Java phức tạp hơn nhiều so với C #. Vì vậy, tôi đã bỏ Java ..."
Mukus

0
//Review the sample enum below for a template on how to implement a JavaEnum.
//There is also an EnumSet implementation below.

public abstract class JavaEnum : IComparable {
    public static IEnumerable<JavaEnum> Values {
        get {
            throw new NotImplementedException("Enumeration missing");
        }
    }

    public readonly string Name;

    public JavaEnum(string name) {
        this.Name = name;
    }

    public override string ToString() {
        return base.ToString() + "." + Name.ToUpper();
    }

    public int CompareTo(object obj) {
        if(obj is JavaEnum) {
            return string.Compare(this.Name, ((JavaEnum)obj).Name);
        } else {
            throw new ArgumentException();
        }
    }


    //Dictionary values are of type SortedSet<T>
    private static Dictionary<Type, object> enumDictionary;
    public static SortedSet<T> RetrieveEnumValues<T>() where T : JavaEnum {
        if(enumDictionary == null) {
            enumDictionary = new Dictionary<Type, object>();
        }
        object enums;
        if(!enumDictionary.TryGetValue(typeof(T), out enums)) {
            enums = new SortedSet<T>();
            FieldInfo[] myFieldInfo = typeof(T).GetFields(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
            foreach(FieldInfo f in myFieldInfo) {
                if(f.FieldType == typeof(T)) {
                    ((SortedSet<T>)enums).Add((T)f.GetValue(null));
                }
            }
            enumDictionary.Add(typeof(T), enums);
        }
        return (SortedSet<T>)enums;
    }
}


//Sample JavaEnum
public class SampleEnum : JavaEnum {
    //Enum values
    public static readonly SampleEnum A = new SampleEnum("A", 1);
    public static readonly SampleEnum B = new SampleEnum("B", 2);
    public static readonly SampleEnum C = new SampleEnum("C", 3);

    //Variables or Properties common to all enums of this type
    public int int1;
    public static int int2 = 4;
    public static readonly int int3 = 9;

    //The Values property must be replaced with a call to JavaEnum.generateEnumValues<MyEnumType>() to generate an IEnumerable set.
    public static new IEnumerable<SampleEnum> Values {
        get {
            foreach(var e in JavaEnum.RetrieveEnumValues<SampleEnum>()) {
                yield return e;
            }
            //If this enum should compose several enums, add them here
            //foreach(var e in ChildSampleEnum.Values) {
            //    yield return e;
            //}
        }
    }

    public SampleEnum(string name, int int1)
        : base(name) {
        this.int1 = int1;
    }
}


public class EnumSet<T> : SortedSet<T> where T : JavaEnum {
    // Creates an enum set containing all of the elements in the specified element type.
    public static EnumSet<T> AllOf(IEnumerable<T> values) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an enum set with the same element type as the specified enum set, initially containing all the elements of this type that are not contained in the specified set.
    public static EnumSet<T> ComplementOf(IEnumerable<T> values, EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            if(!set.Contains(item)) {
                returnSet.Add(item);
            }
        }
        return returnSet;
    }

    // Creates an enum set initially containing all of the elements in the range defined by the two specified endpoints.
    public static EnumSet<T> Range(IEnumerable<T> values, T from, T to) {
        EnumSet<T> returnSet = new EnumSet<T>();
        if(from == to) {
            returnSet.Add(from);
            return returnSet;
        }
        bool isFrom = false;
        foreach(T item in values) {
            if(isFrom) {
                returnSet.Add(item);
                if(item == to) {
                    return returnSet;
                }
            } else if(item == from) {
                isFrom = true;
                returnSet.Add(item);
            }
        }
        throw new ArgumentException();
    }

    // Creates an enum set initially containing the specified element(s).
    public static EnumSet<T> Of(params T[] setItems) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in setItems) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an empty enum set with the specified element type.
    public static EnumSet<T> NoneOf() {
        return new EnumSet<T>();
    }

    // Returns a copy of the set passed in.
    public static EnumSet<T> CopyOf(EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        returnSet.Add(set);
        return returnSet;
    }

    // Adds a set to an existing set.
    public void Add(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Add(item);
        }
    }

    // Removes a set from an existing set.
    public void Remove(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Remove(item);
        }
    }
}

0

Bạn cũng có thể sử dụng một lớp tiện ích cho từng loại enum chứa một thể hiện với dữ liệu nâng cao cho mỗi giá trị enum.

public enum Planet
{
    MERCURY,
    VENUS
}

public class PlanetUtil
{
    private static readonly IDictionary<Planet, PlanetUtil> PLANETS = new Dictionary<Planet, PlanetUtil();

    static PlanetUtil()
    {
        PlanetUtil.PLANETS.Add(Planet.MERCURY, new PlanetUtil(3.303e+23, 2.4397e6));
        PlanetUtil.PLANETS.Add(Planet.VENUS, new PlanetUtil(4.869e+24, 6.0518e6));
    }

    public static PlanetUtil GetUtil(Planet planet)
    {
        return PlanetUtil.PLANETS[planet];
    }

    private readonly double radius;
    private readonly double mass;

    public PlanetUtil(double radius, double mass)
    {
        this.radius = radius;
        this.mass = mass;
    }

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