programing

C#과 Java Enum(C#이 처음인 경우)

prostudy 2022. 6. 25. 19:31
반응형

C#과 Java Enum(C#이 처음인 경우)

한동안 자바에서 프로그래밍을 하다가 완전히 C#로 작성된 프로젝트에 투입되었습니다.C#의 내용을 파악하려고 합니다만, 새로운 프로젝트의 몇 군데에서 enum이 사용되고 있는 것을 알 수 있었습니다만, 언뜻 보면 C#의 enum은 Java 1.5+의 실장보다 심플한 것 같습니다.C#과 Java enum의 차이와 그 차이를 극복하는 방법을 열거할 수 있는 사람이 있습니까?(언어 불꽃 전쟁을 시작하고 싶지는 않습니다.Java에서 했던 C#에서의 조작 방법을 알고 싶을 뿐입니다).예를 들어, 누군가가 Sun의 유명한 Planet 열거형 예제의 C# 대응물을 게시할 수 있습니까?

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 ...]

C#에서는 Enum에 확장 방식을 정의할 수 있습니다.이것에 의해, 부족한 기능의 일부를 보충할 수 있습니다.

할 수 .Planet으로서, 거형으 equival equivalent equival as as 、 한 as as equival equival equival equival 。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
}

CLR의 열거는 단순히 이름이 붙은 상수입니다.기본 형식은 정수여야 합니다.Java에서 열거형은 명명된 유형의 인스턴스에 가깝습니다.이 유형은 매우 복잡할 수 있으며, 예시와 같이 다양한 유형의 필드가 여러 개 포함되어 있습니다.

예를 C#으로 포팅하려면 열거형을 불변 클래스로 변경하고 해당 클래스의 정적 읽기 전용 인스턴스를 표시합니다.

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

C#에서는 속성을 enum과 함께 사용할 수 있습니다.자세한 설명이 포함된 이 프로그래밍 패턴의 좋은 예는 다음과 같습니다(Codeproject).

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

편집: 이 질문은 최근 Jon Sket에 의해 다시 제기되어 답변되었습니다.C#의 Java 열거형과 동등한 것은 무엇입니까?C#의 사설 내부 클래스 - 왜 더 자주 사용하지 않는가?

편집 2: 이 접근방식을 매우 훌륭하게 확장한, 인정된 답변을 참조하십시오.

Java Enum은 실제로는 개인 생성자 및 메서드 등을 가질 수 있는 풀클래스인 반면 C# Enum은 이름 붙여진 정수일 뿐입니다.IMO Java의 구현은 월등히 우수합니다.

이 페이지는 Java 캠프에서 제공되는 c#을 배울 때 많은 도움이 될 입니다.(링크는 enum에 대한 차이점을 나타냅니다(다른 것에 대해서는 위/아래로 스크롤합니다).

제 생각에는 다음과 같습니다.

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와 같은

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

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

기본적으로 유형 매개 변수가 있기 때문에 파생된 여러 열거에서 서수 카운트가 제대로 작동합니다.존 jon jon jonOperatorhttp://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()은 파생된 Enumeration 유형의 각 값에 대해 동일한 결과를 제공합니다.
  • Static의 System.Enum열거하다.

Java 열거는 OO 방식으로 열거를 제시하기 위한 구문설탕입니다.Java에서 Enum 클래스를 확장하는 추상 클래스이며 각 Enum 값은 Enum 클래스의 정적 최종 공개 인스턴스 구현과 같습니다.생성된 클래스를 보면 값이 10개인 열거형 "Foo"의 경우 생성된 "Foo$1" ~ "Foo$10" 클래스가 표시됩니다.

저는 C#을 모릅니다만, 그 언어의 열거형은 C스타일 언어의 전통적인 열거형에 가깝다고 추측할 수 있을 뿐입니다.단, 구글의 빠른 검색에서는 여러 값을 유지할 수 있기 때문에 비슷한 방법으로 구현될 수 있지만 Java 컴파일러가 허용하는 것보다 훨씬 더 많은 제한이 있습니다.

Java Enum을 사용하면 컴파일러가 생성한 valueOf 메서드를 사용하여 이름에서 쉽게 변환할 수 있습니다.

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

C#의 raw enum에 상당하는 것은 보다 상세합니다.

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

Kent에 경로를 따라 sugsted를 할 수 .ValueOf메서드를 지정합니다.

C#의 enum은 CLR 내부 상수일 뿐이지 그다지 친숙하지는 않습니다.Java에서 몇 가지 클래스를 디컴파일했습니다.변환 후 Enums를 원하는 것을 알 수 있습니다.

자바는 교활한 짓을 한다.열거 클래스를 일반 클래스로 취급합니다.이 클래스는 열거 값을 참조할 때 많은 매크로를 사용합니다.Java 클래스에 Enum을 사용하는 대/소문자가 있는 경우 정수에 대한 열거 참조가 대체됩니다.문자열로 이동해야 하는 경우 각 클래스에서 사용하는 서수별로 인덱스된 문자열 배열을 만듭니다.복싱 비용을 절약할 수 있을 것 같다.

이 디컴파일러를 다운로드하면 클래스를 만들고 통합하는 방법을 볼 수 있습니다.솔직히 말하자면 꽤 매력적이네요.나는 열거 클래스가 단지 상수의 배열에 대해 부풀리는 것이라고 생각했기 때문에 그것을 사용하지 않았다.C#에서 사용할 수 있는 제한적인 방법보다 마음에 듭니다.

http://members.fortunecity.com/neshkov/dj.html -- Java 디컴파일러

Java의 열거형은 C# 열거형보다 훨씬 복잡하기 때문에 더 강력합니다.그것은 단지 다른 컴파일 시간 구문설탕이기 때문에, 실제의 응용에 한정된 용도를 가지고 있기 때문에,때로는 사소한 기능을 포함시켜야 한다는 압박감에 굴복하는 것보다 언어에서 무언가를 꺼리는 것이 더 어렵습니다.

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

각 열거형마다 유틸리티 클래스를 사용하여 각 열거형 값에 대한 고급 데이터가 포함된 인스턴스를 유지할 수도 있습니다.

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
}

언급URL : https://stackoverflow.com/questions/469287/c-sharp-vs-java-enum-for-those-new-to-c

반응형