我已经用Java编程了一段时间,只是投入了一个完全用C#编写的项目.我正试图加快C#的速度,并注意到在我的新项目中几个地方使用的枚举,但乍一看,C#的枚举似乎比Java 1.5+实现更简单.任何人都可以枚举C#和Java枚举之间的差异,以及如何克服这些差异?(我不想开始语言火焰战,我只想知道如何在C#中做一些我以前用Java做的事情).例如,有人可以发布一个C#对应的Sun着名的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 ...]
finnw.. 212
在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 }
我认为应该对此进行更多投票.它更接近Java中的枚举工作方式.我可以做一些像Planet.MERCURY.GetSurfaceGravity()< - 注意Enum上的扩展方法! (19认同)
@AllonGuralnek谢谢.不是每个人都会同意元数据.请参阅MattDavey对[相关codereview.stackexchange问题]的评论(http://codereview.stackexchange.com/questions/5352/getting-the-value-of-a-custom-attribute-from-an-enum). (3认同)
肯定是的.Enums上的扩展方法(heck,一般的扩展方法)是C#的一个很好的补充. (2认同)
Kent Boogaar.. 204
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 IEnumerableValues { 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#中以比在Java中更冗长的方式实现的东西几乎是不可思议的 (21认同)
@Chris:只有标志枚举应该是复数.也就是说,使用|组合成员的枚举 运营商. (9认同)
@Mladen:这完全取决于上下文.行星的枚举可能非常适合于提供对有限数量的行星的访问的游戏.如果将新行星添加到游戏中,对代码的更改可能正是您想要的. (5认同)
正是这种类型安全的枚举,我们穷人被迫使用Java 1.4及以下必须实现... Java 5的枚举可能是Java 5+的最佳功能,特别是因为它们可用于switch语句. (3认同)
@Richie_W您可以使用Values属性迭代枚举. (3认同)
@nawfal乍一看我是这么认为的,但与C#不同,java`enum`可以为null.我认为`class`在这个观点上更为相同. (3认同)
好的,我到目前为止得到的答案,我最喜欢这个.这跟我想的一样:如果你想在C#中使用枚举方法,要么将它们改为常量(就像你做的那样),要么将枚举嵌入到实用程序类中(这可能更难用"Planet"示例) . (2认同)
我认为这个例子无论如何都是愚蠢的.如果你想添加一个新星球怎么办?您必须编辑代码.这就是为什么你要使用行星的普通类而不是Java或C#中的枚举. (2认同)
我认为最好使用一个数组来代替`public static IEnumerable
Mikhail.. 34
在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:看到接受的答案,以非常出色的方式扩展这种方法!
在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 }
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 IEnumerableValues { 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#中,属性可以与枚举一起使用.这里有详细描述的编程模式的好例子(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的实现远非优越.
在学习来自java阵营的c#时,这个页面可以帮助你很多.(该链接指向枚举的差异(向上/向下滚动其他内容)