当前位置:  开发笔记 > 编程语言 > 正文

C#vs Java Enum(适用于C#的新手)

如何解决《C#vsJavaEnum(适用于C#的新手)》经验,为你挑选了4个好方法。

我已经用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 IEnumerable 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#中以比在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 Values`,比如`private static Plan [] values = {VIP,CHEAP,MEDIUM,D_PLAN};`.然后它将更接近Java枚举(您可以拥有长度并使用索引访问每个枚举) (2认同)


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:看到接受的答案,以非常出色的方式扩展这种方法!



1> finnw..:

在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上的扩展方法!
@AllonGuralnek谢谢.不是每个人都会同意元数据.请参阅MattDavey对[相关codereview.stackexchange问​​题]的评论(http://codereview.stackexchange.com/questions/5352/getting-the-value-of-a-custom-attribute-from-an-enum).
肯定是的.Enums上的扩展方法(heck,一般的扩展方法)是C#的一个很好的补充.

2> Kent Boogaar..:

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 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#中以比在Java中更冗长的方式实现的东西几乎是不可思议的
@Chris:只有标志枚举应该是复数.也就是说,使用|组合成员的枚举 运营商.
@Mladen:这完全取决于上下文.行星的枚举可能非常适合于提供对有限数量的行星的访问的游戏.如果将新行星添加到游戏中,对代码的更改可能正是您想要的.
正是这种类型安全的枚举,我们穷人被迫使用Java 1.4及以下必须实现... Java 5的枚举可能是Java 5+的最佳功能,特别是因为它们可用于switch语句.
@Richie_W您可以使用Values属性迭代枚举.
@nawfal乍一看我是这么认为的,但与C#不同,java`enum`可以为null.我认为`class`在这个观点上更为相同.
好的,我到目前为止得到的答案,我最喜欢这个.这跟我想的一样:如果你想在C#中使用枚举方法,要么将它们改为常量(就像你做的那样),要么将枚举嵌入到实用程序类中(这可能更难用"Planet"示例) .
我认为这个例子无论如何都是愚蠢的.如果你想添加一个新星球怎么办?您必须编辑代码.这就是为什么你要使用行星的普通类而不是Java或C#中的枚举.
我认为最好使用一个数组来代替`public static IEnumerable Values`,比如`private static Plan [] values = {VIP,CHEAP,MEDIUM,D_PLAN};`.然后它将更接近Java枚举(您可以拥有长度并使用索引访问每个枚举)

3> Mikhail..:

在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:看到接受的答案,以非常出色的方式扩展这种方法!



4> Richard Walt..:

Java枚举实际上是完整的类,可以有私有构造函数和方法等,而C#枚举只是命名为整数.IMO Java的实现远非优越.

在学习来自java阵营的c#时,这个页面可以帮助你很多.(该链接指向枚举的差异(向上/向下滚动其他内容)


...我很好奇你发现了哪些其他错误?
推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有