2009-09-03 3 views
24

C#에서 자바의 열거 형은 무엇입니까?C#에서 Java의 enum과 동일한 것은 무엇입니까?

+2

은 어쩌면 내가 생각 이상 해요,하지만 난했습니다 이미 C#의 열거에 대해 알고 기대하고 언급하는 자바의 열거 몇 가지 기능이있다. 그렇다면 아마도 당신은 당신의 질문에 정교 할 수 있습니다. –

+8

이 질문은 Java'enum'에 대해 아는 것이 있으면 완벽하게 분명합니다. –

+0

@Yishai - C# enums는 기본적으로 Int32이지만 숫자 형식이 될 수 있습니다. –

답변

34

전체 Java enum 기능은 C#에서 사용할 수 없습니다. 당신은 을 합리적으로 중첩 형식과 개인 생성자를 사용하여 닫을 수 있습니다. 예를 들어 : 물론

using System; 
using System.Collections.Generic; 
using System.Xml.Linq; 

public abstract class Operator 
{ 
    public static readonly Operator Plus = new PlusOperator(); 
    public static readonly Operator Minus = 
     new GenericOperator((x, y) => x - y); 
    public static readonly Operator Times = 
     new GenericOperator((x, y) => x * y); 
    public static readonly Operator Divide = 
     new GenericOperator((x, y) => x/y); 

    // Prevent other top-level types from instantiating 
    private Operator() 
    { 
    } 

    public abstract int Execute(int left, int right); 

    private class PlusOperator : Operator 
    { 
     public override int Execute(int left, int right) 
     { 
      return left + right; 
     } 
    } 

    private class GenericOperator : Operator 
    { 
     private readonly Func<int, int, int> op; 

     internal GenericOperator(Func<int, int, int> op) 
     { 
      this.op = op; 
     } 

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

당신은 중첩 된 유형을 사용하는 필요는 없지만 자바 열거가 좋은있는 편리한 "사용자 정의 행위"부분을 제공합니다. 다른 경우에는 private 생성자에 인수를 전달하여 잘 알려진 제한된 값 집합을 가져올 수 있습니다.

몇 일이 당신에게 제공하지 않습니다 :

  • 서수 지원을

의 일부 (싱글)을

  • 스위치 지원
  • EnumSet
  • 직렬화/역 직렬화 스위치가 실제로 해커 없이는 가능하지는 않지만 충분한 노력으로이 작업을 수행 할 수 있습니다. 이제 언어로이 이런 식으로 수행되면 해커를 자동으로 만들어서 스위치 작업을 수행하는 흥미로운 작업을 수행 할 수 있습니다 (예 : const 필드의로드를 자동으로 선언하고 열거 형을 통해 스위치를 정수로 전환하는 등의 변경 만 가능). "알려진"사례를 허용합니다.)

    아, 부분 유형은 같은 파일에 모두의 열거 형 값을 가질 필요가 없음을 의미합니다. 각 값이 상당히 복잡하다면 (분명히 가능합니다) 각각은 자체 파일을 가질 수 있습니다.

  • +0

    int로 암시 적 변환을 사용하여 switch 문 (및 서수)을 지원하는 것이 쉽지 않다고 생각합니까? 나는 무엇을 간과 했는가? –

    +2

    @LimitedAtonement : 사례 식에 필요한 * 상수 * 값을 어떻게 표현 하시겠습니까? –

    +0

    비공개 필드가 정당화 될 때가 거의 없다는 기사를 최근에 읽었습니다. 그 중 한 번인가요? –

    -1

    enum 또는 Java enums가 가지고 있지만 C#이 아닌 것을 특히 필요합니까?

    +0

    Java에서 열거 형은 각 열거 형, 논리가있는 메소드 및 생성자에 대해 여러 개의 연관된 값을 가질 수 있습니다. 최소한 C# 3.0에서 C# enum은 여전히 ​​상수의 목록이며 관련 값을 가질 수 있습니다. –

    +6

    -1 : Java enum은 C# 것보다 훨씬 강력합니다. – Kramii

    +0

    Kramii의 -1에 +1하려면 +1하십시오. C# enum은 이러한 기능 중 일부를 보완하는 확장 메서드를 가질 수 있습니다. – finnw

    17

    열거 형은 C#보다 Java에서 더 잘 구현되는 몇 가지 언어 기능 중 하나입니다. 자바에서 열거 형은 형식의 명명 된 인스턴스이며, C# 열거 형은 기본적으로 상수로 명명됩니다.

    즉, 기본적인 경우에 대해서는 비슷하게 보입니다. 그러나 자바에서는 완전한 eneds 클래스이기 때문에 개별 enum에 동작을 추가 할 수 있다는 점에서보다 강력합니다.

    당신이 찾고있는 특정 기능이 있습니까?

    +8

    Java enum 값과 달리 상수에 사용자 정의 * 동작 *을 사용할 수 없으므로 "동일하게 작동합니다"- IMO가 아닙니다. –

    +2

    그래, 따라서 '기본 사용을위한 자격'. 자바 enums에 대한 좋은 점 중 하나가 사용자 정의 동작이라는 점에 동의합니다. – Chi

    +1

    저는 C# Enum보다 Java Enum을 좋아합니다. C# Enums를 사용하면 Switch Statements Smell을 널리 분산시킬 수 있으며 스위치 문에 흩어져있는 많은 코드가 각 Enum과 관련된 메소드로 배치 될 수 있습니다. – thenonhacker

    4

    아마도 우리가 자바를 사용하기 전에 자바에서 사용했던 오래된 typesafe enum 패턴을 사용할 수 있습니다. (C#의 것들은 주석 클레임의 클래스가 아닙니다.) 패턴은 중간 바로 전에 기술되어 있습니다 this page

    +0

    +1 : 제가 사용하는 접근법입니다. – Kramii

    5

    또 다른 흥미로운 아이디어가 있습니다. 나는 다음과 같은 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; } 
        } 
    } 
    

    은 기본적으로 너무 서수 수는 다른 파생 열거를 통해 제대로 작동합니다.Jon의 Operator 위의 예는 다음과 같습니다.

    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의 정적 메서드를 기본 Enumeration 클래스에 추가하여 동일한 기능을 사용할 수 있습니다.
    +0

    저는 자바를 C#으로 변환하려고합니다. 그래서 한달 전에 답을봤을 때 '내 요구에 너무 많은 문제가 생겼습니다'라고 생각했습니다 ... 지금 다시 필요합니다. '(문자열) 이름으로 열거 형 검색'기능. 명성! –

    +0

    @Andrew Cooper, re : "이것은 몇 가지 이점을 제공합니다. * Ordinal 지원 * switch 문을 실현할 수 있도록 string 및 int로 변환"- 컴파일러가 case 문에 상수 값이 필요하다는 이유로 불필요한 switch 문을 지원하지 않는 것 같습니다 . 그것은 (int) cast 나 .Ordinal 값을 const로 받아들이지 않습니다. – tomosius

    1
    //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); 
         } 
        } 
    } 
    
    관련 문제