나는 한동안 Java로 프로그래밍 해 왔으며 C #으로 작성된 프로젝트에 방금 던져졌습니다. C #에서 속도를 높이려고 노력 중이며 새 프로젝트의 여러 곳에서 열거 형이 사용되는 것을 보았지만 언뜻보기에 C #의 열거 형은 Java 1.5 + 구현보다 단순한 것으로 보입니다. 누구나 C #과 Java 열거 형의 차이점과 차이점을 극복하는 방법을 열거 할 수 있습니까? (언어 화염 전쟁을 시작하고 싶지 않고 Java에서했던 C #에서 몇 가지 작업을 수행하는 방법을 알고 싶습니다.) 예를 들어 누군가 Sun의 유명한 Planet enum 예제에 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 ...]
답변
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 #에서는 열거 형에 대한 확장 메서드 를 정의 할 수 있으며 이로 인해 누락 된 기능 중 일부가 보완됩니다.
당신은 정의 할 수 있습니다 Planet
열거로도에 해당 확장 방법을 가지고 surfaceGravity()
와 surfaceWeight()
.
Mikhail이 제안한 사용자 정의 속성을 사용 했지만 Dictionary를 사용하여 동일한 속성을 얻을 수 있습니다.
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
}
답변
C #에서 속성은 열거 형과 함께 사용할 수 있습니다. 자세한 설명과 함께이 프로그래밍 패턴의 좋은 예는 다음과 같습니다 (Codeproject)
public enum Planet
{
[PlanetAttr(3.303e+23, 2.4397e6)]
Mercury,
[PlanetAttr(4.869e+24, 6.0518e6)]
Venus
}
편집 : 이 질문은 최근에 다시 요청되었고 Jon Skeet에 의해 답변되었습니다 .C #에서 Java의 열거 형과 동등한 것은 무엇입니까?
C #의 개인 내부 클래스-왜 더 자주 사용하지 않습니까?
편집 2 : 이 접근법을 매우 화려한 방식으로 확장 하는 수용 된 답변 을보십시오!
답변
Java 열거 형은 실제로 개인 생성자와 메서드 등을 가질 수있는 전체 클래스이며 C # 열거 형은 정수입니다. IMO Java의 구현은 훨씬 우수합니다.
이 페이지는 자바 캠프에서 오는 C #을 배우는 동안 많은 도움이 될 것입니다. (링크는 열거 형의 차이점을 나타냅니다 (다른 것들을 위아래로 스크롤)
답변
내가 생각하는 이와 같은 것 :
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
위와 같이 상수를 클래스에 결합하십시오.
답변
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 Skeet의 Operator
다른 질문에 대한 그의 답변 (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
동일한 기능을 허용하도록 기본 열거 클래스에 추가 할 수 있습니다.
답변
우리는 방금 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)
{
}
}