C # vs Java Enum (สำหรับผู้ที่เพิ่งเริ่มใช้ C #)


182

ฉันเคยเขียนโปรแกรมใน Java มาระยะหนึ่งแล้วเพิ่งถูกโยนลงในโปรเจ็กต์ที่เขียนด้วยภาษา C # ทั้งหมด ฉันพยายามที่จะเพิ่มความเร็วใน C # และสังเกตว่า enums ใช้ในหลาย ๆ ที่ในโครงการใหม่ของฉัน แต่จากการมองเห็นครั้งแรก Enums ของ C # ดูเหมือนจะง่ายกว่าการใช้ Java 1.5+ ใครสามารถระบุความแตกต่างระหว่าง C # และ Java enums และวิธีการเอาชนะความแตกต่าง? (ฉันไม่ต้องการที่จะเริ่มสงครามภาษาเปลวไฟฉันแค่อยากรู้วิธีทำบางสิ่งใน C # ที่ฉันเคยทำใน Java) ตัวอย่างเช่นใครบางคนสามารถโพสต์คู่ C # ให้กับตัวอย่างที่เป็นที่นิยมของ Planet ได้หรือไม่?

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 ฉันไม่สามารถเครดิตได้ มันมาจาก Sun (ตอนนี้ Oracle): docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Ogre Psalm33

คำตอบ:


210

การแจกแจงใน CLR เป็นเพียงค่าคงที่ ประเภทพื้นฐานจะต้องเป็นส่วนประกอบ ใน Java การแจงนับเป็นเหมือนตัวอย่างที่มีชื่อของประเภท ประเภทนั้นอาจค่อนข้างซับซ้อนและ - ตามตัวอย่างของคุณแสดง - มีหลายฟิลด์ของประเภทต่างๆ

ในการพอร์ตตัวอย่างเป็น C # ฉันเพิ่งจะเปลี่ยน enum เป็นคลาสที่ไม่เปลี่ยนรูปและแสดงให้เห็นตัวอย่างคงที่อ่านได้อย่างเดียวของชั้นเรียนที่:

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
เป็น enum ประเภทที่ปลอดภัยแบบนี้ที่คนจนเราบังคับให้ใช้ Java 1.4 และต่ำกว่าต้องติดตั้ง ... enums ของ Java 5 อาจเป็นคุณสมบัติที่ดีที่สุดของ Java 5+ โดยเฉพาะอย่างยิ่งเนื่องจากสามารถใช้ในงบสวิตช์ได้
MetroidFan2002

9
@Chris: เฉพาะค่า enums เท่านั้นที่ควรเป็นพหูพจน์ นั่นคือการแจกแจงที่สมาชิกรวมกันโดยใช้ | ผู้ประกอบการ
Kent Boogaart

5
@ Laden: มันขึ้นอยู่กับบริบททั้งหมด การนับจำนวนดาวเคราะห์อาจเหมาะสมกับเกมที่ให้การเข้าถึงดาวเคราะห์จำนวน จำกัด การเปลี่ยนแปลงรหัสอาจเป็นสิ่งที่คุณต้องการอย่างแน่นอนหากมีการเพิ่มดาวเคราะห์ดวงใหม่ในเกม
Kent Boogaart

3
@Richie_W คุณสามารถวนซ้ำ enums โดยใช้คุณสมบัติ Values
Jonathan

23
ว้าว ... แทบไม่น่าเชื่อที่จะเห็นบางสิ่งที่ถูกนำไปใช้อย่างละเอียดใน C # มากกว่าใน Java
Sune Rasmussen

218

ใน C # คุณสามารถกำหนดวิธีการขยายบน enums และสิ่งนี้ทำขึ้นสำหรับการทำงานที่ขาดหายไปบางส่วน

คุณสามารถกำหนดPlanetเป็น enum และยังมีวิธีการขยายเทียบเท่ากับและsurfaceGravity()surfaceWeight()

ฉันได้ใช้คุณสมบัติที่กำหนดเองตามที่Mikhailแนะนำแต่ก็สามารถทำได้ด้วยพจนานุกรม

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
ฉันคิดว่าสิ่งนี้ควรได้รับการโหวตมากขึ้น มันใกล้เคียงกับการทำงานของ enums ใน Java ฉันสามารถทำบางอย่างเช่น Planet.MERCURY.GetSurfaceGravity () <- หมายเหตุวิธีการขยายใน Enum!
thenonhacker

2
ใช่แน่นอน วิธีการขยายใน Enums (heck, วิธีการขยายโดยทั่วไป) เป็นส่วนเสริมที่ดีใน C #
KeithS

3
@AllonGuralnek ขอบคุณ ไม่ใช่ทุกคนที่จะเห็นด้วยกับข้อมูลเมตา ดูความคิดเห็น MattDavey ในคำถาม codereview.stackexchange ที่เกี่ยวข้อง
finnw

@finnw: ฉันไม่เคยได้ยินเว็บไซต์ Code Review SE - ขอบคุณสำหรับสิ่งนั้น! ฉันได้ทำการสนทนานี้ต่อที่นั่น (แม้ว่ามันอาจสมควรได้รับคำถามของตัวเองที่นี่ในโปรแกรมเมอร์)
Allon Guralnek

นี่เป็นทางออกที่ดี - มีใครทดสอบประสิทธิภาพของสิ่งนี้หรือไม่ เช่นใช้เวลานานแค่ไหนในการเข้าถึงแอททริบิวเมื่อเทียบกับการเข้าถึงคุณสมบัติของคลาส
Simon Meyer

35

ในคุณลักษณะ C # สามารถใช้กับ enums ตัวอย่างที่ดีของรูปแบบการเขียนโปรแกรมนี้พร้อมคำอธิบายโดยละเอียดอยู่ที่นี่ (Codeproject)

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

แก้ไข:คำถามนี้ถูกถามเมื่อเร็ว ๆ นี้อีกครั้งและตอบโดย Jon Skeet: อะไรคือสิ่งที่เทียบเท่ากับ enum ของ Java ใน C #? ชั้นเรียนส่วนตัวใน C # - ทำไมพวกเขาไม่ใช้บ่อยกว่านี้?

แก้ไข 2:ดูคำตอบที่ยอมรับซึ่งขยายแนวทางนี้ในวิธีที่ยอดเยี่ยมมาก!


1
ดี! สิ่งนี้ให้ความรู้สึกเพียงเล็กน้อย แต่ก็เป็นวิธีที่ยอมรับได้ในการเพิ่มข้อมูลพิเศษให้กับ enum ฉันประหลาดใจตรงไปตรงมาว่ามันต้องใช้เวลากับใครซักคนที่จะพูดถึงทางออกที่ยอดเยี่ยมนี้
Ogre Psalm33

13

Java enums เป็นคลาสเต็มรูปแบบที่สามารถมี Constructor ส่วนตัวและวิธีการอื่น ๆ ในขณะที่ C # enums เป็นชื่อจำนวนเต็ม การใช้งาน IMO Java นั้นเหนือกว่าอย่างมาก

หน้านี้จะช่วยคุณได้มากในขณะที่การเรียนรู้ c # มาจากค่าย java (ลิงก์ชี้ไปที่ความแตกต่างเกี่ยวกับ enums (เลื่อนขึ้น / ลงเพื่อทำสิ่งอื่น ๆ )


1
แม้ว่าลิงก์ของคุณจะให้ภาพรวมที่น่าสนใจและครอบคลุมถึงความเหมือนและความแตกต่างระหว่าง C # และ Java แต่ก็มีข้อผิดพลาดมากมายในข้อความ (เช่นการระบุอย่างผิด ๆ ว่า Java ได้รับการป้องกันเท่ากับ C # ภายในขณะที่ควรได้รับการป้องกันภายใน) ดังนั้นไม่ได้ใช้ทุกอย่างที่มีเพื่อรับ :)
Mafu

1
ฉันจะไม่พูดว่า Java enums ยอดเยี่ยมแม้ว่าฉันจะเป็นแฟนของ java C # รองรับการประกาศจำนวนเต็มอย่างง่ายเช่นFOO = 0ซึ่งง่ายต่อการใช้งานในเครื่องมือ ORM (ไม่ordinal()จำเป็นต้องมีข้อผิดพลาดในการใช้งาน) นอกจากนี้ C # สนับสนุน Bitwise enumerations EntityFrameworkซึ่งมักจะมีประโยชน์มากโดยเฉพาะอย่างยิ่งในการรวมกันกับ Java ควรขยาย enums ของพวกเขาเพื่อให้พวกเขาสามารถผูกกับจำนวนเต็มเกินไป จากนั้นพวกเขาก็จะดีกว่า :)
djmj

4

อย่างนี้ฉันคิดว่า:

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

หรือรวมค่าคงที่เข้ากับPlanetคลาสดังกล่าว


8
ไม่มากนักตัวสร้างดาวเคราะห์ควรเป็นแบบส่วนตัว ส่วนหนึ่งของประเด็น enums คือมันเป็นค่าคงที่ ค่าก็จะถูกกำหนดในชั้นดาวเคราะห์ด้วย
Jon Skeet

ยัง. 1) ตัวแจงนับหายไป :) 2) ไม่ควรเปลี่ยนค่า enums โอ้และสุดท้ายรหัสของคุณขอหนึ่งชั้นเรียนเดียว (โดยเฉพาะเมื่อคุณมี
คอนสตรั

3

ต่อไปนี้เป็นแนวคิดที่น่าสนใจอีกประการหนึ่งที่ให้บริการสำหรับพฤติกรรมที่กำหนดเองที่มีอยู่ใน Java ฉันมากับEnumerationคลาสฐานต่อไปนี้:

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

มันมีพารามิเตอร์ประเภทโดยทั่วไปเพียงแค่การนับลำดับจะทำงานอย่างถูกต้องในการแจกแจงที่แตกต่างกัน Operatorตัวอย่างของ Jon Skeet จากคำตอบของเขาสำหรับคำถามอื่น (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) ด้านบนจะกลายเป็น:

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

นี่เป็นข้อได้เปรียบบางประการ

  • การสนับสนุนตามลำดับ
  • การแปลงเป็นstringและintทำให้คำสั่งสวิตช์เป็นไปได้
  • GetType () จะให้ผลลัพธ์เหมือนกันสำหรับแต่ละค่าของประเภทการแจงนับที่ได้รับ
  • System.Enumสามารถเพิ่มวิธีการแบบคงที่จากลงในคลาสการแจงนับพื้นฐานเพื่อให้มีฟังก์ชันการทำงานเดียวกัน

3

เราเพิ่งสร้างส่วนขยาย enum สำหรับ c # https://github.com/simonmau/enum_ext

มันเป็นเพียงการนำไปใช้สำหรับ typesafeenum แต่มันใช้งานได้ดีมากเราจึงทำแพ็คเกจเพื่อแชร์ - สนุกกับมัน

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

Java enum เป็นน้ำตาลเชิงประโยคเพื่อแสดง enumerations ในลักษณะ OO พวกเขาเป็นคลาสนามธรรมที่ขยายคลาส Enum ใน Java และค่า enum แต่ละรายการจะเหมือนกับการใช้งานอินสแตนซ์สาธารณะสุดท้ายสุดท้ายของคลาส enum ดูคลาสที่สร้างขึ้นและสำหรับ enum "Foo" ที่มี 10 ค่าคุณจะเห็น "Foo $ 1" ถึงคลาส "Foo $ 10" ที่สร้าง

ฉันไม่รู้ C # แต่ฉันสามารถคาดเดาได้ว่า enum ในภาษานั้นเป็นเหมือน enum ดั้งเดิมในภาษาสไตล์ C ฉันเห็นจากการค้นหาโดย Google อย่างรวดเร็วว่าพวกเขาสามารถเก็บค่าได้หลายค่าดังนั้นจึงอาจนำไปใช้ในลักษณะที่คล้ายกัน แต่มีข้อ จำกัด มากกว่าสิ่งที่ Java คอมไพเลอร์อนุญาต


3
ทุกอย่างไม่ใน Java และ C # ทั้งหมดเกี่ยวกับน้ำตาล syntactic สำหรับ JVM หรือ CLR bytecodes? :) เพียงแค่บอกว่า
นั้นใน

2

Java enums อนุญาตให้การแปลง typesafe ง่าย ๆ จากชื่อโดยใช้เมธอด valueOf ที่สร้างโดยคอมไพเลอร์เช่น

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

สิ่งที่เทียบเท่ากับ enum แบบดิบใน C # นั้นมีรายละเอียดมากขึ้น:

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

อย่างไรก็ตามหากคุณลงไปตามเส้นทางที่ได้รับจาก Kent คุณสามารถใช้ValueOfวิธีการในชั้นเรียน Enum ของคุณได้อย่างง่ายดาย


ตัวอย่าง Java ใช้วิธีการสังเคราะห์ที่คอมไพเลอร์สร้างขึ้นโดยไม่เกี่ยวข้องกับยาชื่อสามัญเลย Enum มีเมธอด valueOf ทั่วไป แต่ใช้ generics ของ Class ไม่ใช่ของ Enum
Tom Hawtin - tackline

2

ฉันสงสัยว่า enums ใน C # เป็นเพียงค่าคงที่ภายใน CLR แต่ไม่คุ้นเคยกับพวกเขา ฉันได้แยกคลาสบางส่วนใน Java แล้วและฉันบอกได้เลยว่าคุณต้องการ Enums เมื่อคุณแปลง

Java ทำสิ่งที่ลับ ๆ ล่อๆ มันถือว่าคลาส enum เป็นคลาสปกติด้วยใกล้ที่สุดเท่าที่ฉันสามารถคิดได้โดยใช้มาโครจำนวนมากเมื่ออ้างอิงค่า enum หากคุณมีคำสั่ง case ในคลาส Java ที่ใช้ enums มันจะแทนที่ enum ที่อ้างอิงถึงจำนวนเต็ม หากคุณต้องการไปที่สตริงมันจะสร้างอาร์เรย์ของสตริงที่จัดทำดัชนีโดยลำดับที่ใช้ในแต่ละคลาส ฉันสงสัยว่าจะประหยัดในการชกมวย

ถ้าคุณดาวน์โหลดตัวถอดรหัสนี้คุณจะได้เห็นว่ามันสร้างคลาสได้อย่างไรและผสานเข้ากับมันอย่างไร ค่อนข้างน่าหลงใหลที่จะซื่อสัตย์ ฉันไม่เคยใช้คลาสเอนัมเพราะฉันคิดว่ามันคงป่องสำหรับค่าคงที่มากมาย ฉันชอบมันมากกว่าวิธีที่ จำกัด คุณสามารถใช้มันใน C #

http://members.uckyecity.com/neshkov/dj.html - decompiler Java


0

Enum ใน Java นั้นซับซ้อนกว่า C # enum และมีประสิทธิภาพมากกว่า เนื่องจากมันเป็นเพียงการรวบรวมเวลาสร้างประโยคน้ำตาลฉันสงสัยว่ามันคุ้มค่าที่จะรวมภาษาที่มีการใช้งานที่ จำกัด ในการใช้งานจริง บางครั้งมันยากที่จะกำจัดสิ่งต่าง ๆ ออกจากภาษาได้มากกว่าการยอมแพ้ต่อการรวมคุณสมบัติเล็กน้อย


2
ฉันไม่เห็นด้วยอย่างเคารพ Java 1.5 enums เป็นคุณสมบัติทางภาษาที่ทรงพลังที่ฉันได้ใช้หลายครั้งในการปรับใช้โซลูชัน OO-centric ให้มากขึ้นเพื่อแก้ไขปัญหาที่เกิดขึ้นจากชุดค่าคงที่ของรายการที่ไม่ต่อเนื่อง
Ogre Psalm33

1
อาจเป็นเช่นนั้น แต่นอกเหนือจากการรวมภาษา 'สวิตช์' ที่ชาญฉลาดส่วนที่เหลือของฟังก์ชั่นสามารถทำซ้ำได้อย่างง่ายดายใน C # หรือ Java เองตามตัวอย่างข้างต้นแสดงให้เห็น
dmihailescu

@dmihailescu "จากนั้น enum ใน Java มีความซับซ้อนมากกว่า C # ดังนั้นฉันจึงลด 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

คุณสามารถใช้คลาสยูทิลิตี้สำหรับแต่ละประเภท enum ซึ่งเก็บอินสแตนซ์ที่มีข้อมูลขั้นสูงสำหรับแต่ละค่า 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
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.