C # vs Java Enum (bagi yang baru mengenal C #)

182

Saya sudah pemrograman di Jawa untuk sementara waktu dan baru saja dilempar ke proyek yang sepenuhnya ditulis dalam C #. Saya mencoba untuk mempercepat di C #, dan memperhatikan enum yang digunakan di beberapa tempat di proyek baru saya, tetapi pada pandangan pertama, enum C # tampaknya lebih sederhana daripada implementasi Java 1.5+. Adakah yang bisa menyebutkan perbedaan antara C # dan Java enum, dan bagaimana cara mengatasi perbedaan? (Saya tidak ingin memulai perang api bahasa, saya hanya ingin tahu bagaimana melakukan beberapa hal dalam C # yang biasa saya lakukan di Jawa). Sebagai contoh, dapatkah seseorang memposting rekan C # ke Planet Sun yang terkenal sebagai contoh?

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 ...]
Ogre Psalm33
sumber
1
@ comp Saya tidak bisa mengambil kredit untuk itu. Itu berasal dari Sun (sekarang Oracle): docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Ogre Psalm33

Jawaban:

210

Penghitungan dalam CLR hanya disebut konstanta. Jenis yang mendasarinya harus integral. Di Jawa enumerasi lebih seperti turunan dari tipe. Jenis itu bisa sangat kompleks dan - seperti contoh Anda tunjukkan - mengandung banyak bidang dari berbagai jenis.

Untuk mem-port contoh ke C # saya hanya akan mengubah enum ke kelas yang tidak dapat diubah dan mengekspos instance readonly statis dari kelas itu:

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;
    }
}
Kent Boogaart
sumber
4
Ini jenis enum yang aman yang kami orang miskin yang terpaksa menggunakan Java 1.4 dan di bawahnya harus menerapkan ... Enum Java 5 mungkin adalah fitur terbaik Java 5+, terutama karena mereka dapat digunakan dalam pernyataan peralihan.
MetroidFan2002
9
@ Chris: hanya flag enum yang harus jamak. Yaitu, enumerasi yang anggota-anggotanya digabungkan menggunakan | operator.
Kent Boogaart
5
@Mladen: Tergantung sepenuhnya pada konteksnya. Enumerasi planet mungkin sangat cocok untuk permainan yang menyediakan akses ke sejumlah planet. Perubahan pada kode mungkin persis seperti yang Anda inginkan jika sebuah planet baru ditambahkan ke dalam gim.
Kent Boogaart
3
@Richie_W Anda dapat beralih di atas enum menggunakan properti Nilai.
Jonathan
23
Wow ... Hampir tidak dapat dipercaya untuk melihat sesuatu diimplementasikan dalam cara yang lebih verbose di C # daripada di Jawa
Sune Rasmussen
218

Di C # Anda dapat menentukan metode ekstensi pada enum, dan ini membuat beberapa fungsi yang hilang.

Anda dapat mendefinisikan Planetsebagai enum dan juga memiliki metode ekstensi yang setara dengan surfaceGravity()dan surfaceWeight().

Saya telah menggunakan atribut khusus seperti yang disarankan oleh Mikhail , tetapi hal yang sama dapat dicapai menggunakan Kamus.

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
}
menemukan
sumber
20
Saya pikir ini harus lebih banyak dipilih. Ini lebih dekat dengan bagaimana enum di Jawa bekerja. Saya dapat melakukan sesuatu seperti Planet.MERCURY.GetSurfaceGravity () <- Perhatikan metode ekstensi pada Enum!
thenonhacker
2
Pasti ya. Metode ekstensi pada Enums (heck, metode ekstensi secara umum) adalah tambahan yang bagus untuk C #.
KeithS
3
@ AllonGuralnek Terima kasih. Tidak semua orang akan setuju tentang metadata. Lihat komentar MattDavey pada pertanyaan codereview.stackexchange terkait .
finnw
@finnw: Saya belum pernah mendengar tentang situs Code Review SE - terima kasih untuk itu! Saya telah melanjutkan diskusi ini di sana (walaupun mungkin pantas mendapatkan pertanyaannya sendiri di Programmer).
Allon Guralnek
ini adalah solusi hebat - adakah yang menguji kinerja ini? mis. berapa lama waktu yang dibutuhkan untuk mengakses atribut, dibandingkan dengan mengakses properti suatu kelas.
Simon Meyer
35

Dalam C # atribut dapat digunakan dengan enum. Contoh yang bagus dari pola pemrograman ini dengan deskripsi terperinci ada di sini (Codeproject)

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

Sunting: pertanyaan ini baru-baru ini ditanyakan lagi dan dijawab oleh Jon Skeet: Apa yang setara dengan enum Java di C #? Kelas dalam pribadi di C # - mengapa mereka tidak digunakan lebih sering?

Sunting 2: lihat jawaban yang diterima yang memperluas pendekatan ini dengan cara yang sangat brilian!

Mikhail
sumber
1
Bagus! Ini terasa hanya sedikit kikuk, tetapi sebaliknya merupakan metode yang sangat dapat diterima untuk menambahkan data tambahan ke enum. Sejujurnya saya kagum bahwa seseorang membutuhkan waktu selama ini untuk menyebutkan solusi hebat ini!
Ogre Psalm33
13

Java enum sebenarnya adalah kelas penuh yang dapat memiliki konstruktor dan metode pribadi dll, sedangkan C # enums hanya bernama integer. Implementasi IMO Java jauh lebih unggul.

Halaman ini akan banyak membantu Anda saat belajar c # berasal dari sebuah java camp. (Tautan menunjuk ke perbedaan tentang enum (gulir ke atas / bawah untuk hal-hal lain)

Richard Walton
sumber
1
Sementara tautan Anda memberikan ikhtisar yang luas dan menarik tentang persamaan dan perbedaan antara C # dan Java, ada banyak kesalahan dalam teks (mis. Menyatakan bahwa Java protected sama dengan C # internal sementara itu harus dilindungi internal). Jadi jangan mengambil segala sesuatu ada untuk diberikan :)
Mafu
1
Saya tidak akan mengatakan enum Java lebih unggul bahkan jika saya seorang penggemar java. C # mendukung deklarasi integer mudah seperti FOO = 0yang lebih mudah digunakan dalam alat ORM (tidak ordinal()perlu penggunaan rawan kesalahan ). Selanjutnya C # mendukung enumerasi bitwise yang seringkali sangat berguna, terutama dalam kombinasi dengan EntityFramework. Java harus memperluas enum mereka untuk memungkinkan mereka diikat ke bilangan bulat juga. Maka mereka akan lebih unggul :)
djmj
4

Sesuatu seperti ini saya pikir:

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

Atau gabungkan konstanta ke dalam Planetkelas seperti di atas

Chris S
sumber
8
Tidak cukup - pembangun Planet harus bersifat pribadi; bagian dari titik enum adalah bahwa nilai-nilai itu adalah seperangkat nilai yang tetap. Nilai-nilai kemudian akan didefinisikan dalam kelas Planet juga.
Jon Skeet
Belum. 1) enumerator tidak ada :) 2) enum tidak boleh bisa berubah. Oh dan terakhir, kode Anda meminta satu kelas tunggal (khususnya ketika Anda memiliki konstruktor pribadi)
nawfal
3

Berikut ini ide menarik lainnya yang melayani perilaku khusus yang tersedia di Jawa. Saya datang dengan Enumerationkelas dasar berikut :

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

Itu punya tipe parameter pada dasarnya hanya sehingga jumlah ordinal akan bekerja dengan baik di berbagai penghitungan turunan. OperatorContoh Jon Skeet dari jawaban atas pertanyaan lain (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) di atas kemudian menjadi:

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

Ini memberi beberapa keuntungan.

  • Dukungan biasa
  • Konversi ke stringdan intyang membuat pernyataan peralihan layak
  • GetType () akan memberikan hasil yang sama untuk masing-masing nilai dari tipe Enumerasi yang diturunkan.
  • Metode Statis dari System.Enumdapat ditambahkan ke kelas Pencacahan dasar untuk memungkinkan fungsi yang sama.
Andrew Cooper
sumber
3

kami baru saja membuat ekstensi enum untuk c # https://github.com/simonmau/enum_ext

Ini hanya implementasi untuk typesafeenum, tetapi berfungsi dengan baik sehingga kami membuat paket untuk dibagikan - bersenang-senanglah dengannya

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)
    {
    }
}
simonmau
sumber
2

Java enum adalah gula sintaksis untuk menyajikan enumerasi dengan cara OO. Mereka adalah kelas abstrak yang memperluas kelas Enum di Jawa, dan setiap nilai enum seperti implementasi instance publik akhir statis dari kelas enum. Lihatlah kelas yang dihasilkan, dan untuk enum "Foo" dengan 10 nilai, Anda akan melihat "Foo $ 1" hingga "Foo $ 10" dihasilkan.

Saya tidak tahu C #, saya hanya bisa berspekulasi bahwa enum dalam bahasa itu lebih seperti enum tradisional dalam bahasa gaya C. Saya melihat dari pencarian Google cepat bahwa mereka dapat menyimpan beberapa nilai, jadi mereka mungkin diimplementasikan dengan cara yang sama, tetapi dengan batasan yang jauh lebih banyak daripada yang diizinkan oleh kompiler Java.

Astaga
sumber
3
Ya, bukankah semua yang ada di Jawa dan C # tentang gula sintaksis untuk bytecode JVM atau CLR? :) Katakan saja '
thenonhacker
2

Java enum memungkinkan konversi typesafe mudah dari nama menggunakan metode valueOf yang dihasilkan kompiler, yaitu

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

Persamaan untuk enum mentah dalam C # lebih verbose:

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

Namun, jika Anda turun rute sugegsted oleh Kent, Anda dapat dengan mudah menerapkan ValueOfmetode di kelas enum Anda.

serg10
sumber
Contoh Java menggunakan metode sintetis yang dihasilkan oleh kompiler - tidak ada hubungannya dengan obat generik sama sekali. Enum memang memiliki metode generik valueOf, tetapi yang menggunakan generik Class 'dan bukan Enum.
Tom Hawtin - tackline
2

Saya curiga enum dalam C # hanyalah konstanta internal CLR, tetapi tidak terlalu familiar dengan mereka. Saya telah mendekompilasi beberapa kelas di Java dan saya dapat memberi tahu Anda bahwa Enums adalah saat Anda mengonversi.

Java melakukan sesuatu yang licik. Ini memperlakukan kelas enum sebagai kelas normal dengan, sedekat yang saya bisa bayangkan, menggunakan banyak makro ketika merujuk nilai enum. Jika Anda memiliki pernyataan kasus di kelas Java yang menggunakan enum, itu menggantikan referensi enum ke integer. Jika Anda perlu pergi ke string, itu menciptakan array string yang diindeks oleh ordinal yang digunakan di setiap kelas. Saya menduga untuk menghemat tinju.

Jika Anda mengunduh dekompiler ini, Anda akan dapat melihat bagaimana ia membuat kelasnya dan mengintegrasikannya. Agak menarik untuk jujur. Dulu saya tidak menggunakan kelas enum karena saya pikir itu membengkak hanya untuk array konstanta. Saya menyukainya lebih baik daripada cara terbatas Anda dapat menggunakannya dalam C #.

http://members.fortunecity.com/neshkov/dj.html - dekompiler Java

Paul Bruner
sumber
0

Enum di Jawa jauh lebih kompleks daripada C # enum dan karenanya lebih kuat. Karena ini hanyalah gula waktu kompilasi sintaksis lainnya, saya bertanya-tanya apakah benar-benar layak untuk memasukkan bahasa yang diberikan penggunaannya yang terbatas dalam aplikasi kehidupan nyata. Terkadang lebih sulit menjauhkan hal-hal dari bahasa daripada menyerah pada tekanan untuk memasukkan fitur minor.

dmihailescu
sumber
2
Dengan hormat saya tidak setuju. Java 1.5 enum adalah fitur bahasa yang kuat yang telah saya gunakan berkali-kali untuk mengimplementasikan solusi yang lebih OO-sentris untuk masalah yang berhubungan dengan set diskrit dari item bernama konstan.
Ogre Psalm33
1
Mungkin Anda melakukannya. Tetapi di luar integrasi bahasa 'saklar' yang cerdas, fungsi lainnya dapat dengan mudah direplikasi dalam C # atau Java sendiri seperti contoh di atas.
dmihailescu
@dmihailescu "Kalau begitu enum di Jawa jauh lebih kompleks daripada C #. Jadi saya menjatuhkan 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);
        }
    }
}
Jim
sumber
0

Anda juga bisa menggunakan kelas utilitas untuk setiap jenis enum yang menyimpan instance dengan data lanjutan untuk setiap nilai 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
}
djmj
sumber