C # vs Java Enum (para quem é novo em C #)

182

Eu tenho programado em Java por um tempo e acabei de ser lançado em um projeto que é inteiramente escrito em C #. Estou tentando acelerar o processo em C # e notei enumerações usadas em vários lugares no meu novo projeto, mas, à primeira vista, as enumerações em C # parecem ser mais simplistas que a implementação do Java 1.5+. Alguém pode enumerar as diferenças entre enumerações C # e Java e como superar as diferenças? (Não quero iniciar uma guerra de chamas na linguagem, só quero saber como fazer algumas coisas em C # que costumava fazer em Java). Por exemplo, alguém poderia postar uma contrapartida em C # no famoso exemplo enum Planet da Sun?

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 ...]
Salmo Ogro33
fonte
1
@ycomp Não posso aceitar crédito por isso. Ela vem de Sun (agora Oracle): docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Ogre Psalm33

Respostas:

210

Enumerações no CLR são simplesmente denominadas constantes. O tipo subjacente deve ser integral. Em Java, uma enumeração é mais como uma instância nomeada de um tipo. Esse tipo pode ser bastante complexo e - como mostra o exemplo - conter vários campos de vários tipos.

Para portar o exemplo para C #, eu mudaria o enum para uma classe imutável e exporia instâncias estáticas somente leitura dessa classe:

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;
    }
}
Kent Boogaart
fonte
4
É esse tipo de enumeração de tipo seguro que nós, pobres, forçados a usar o Java 1.4 e abaixo, temos que implementar ... As enumerações do Java 5 são talvez a melhor característica do Java 5+, especialmente porque elas podem ser usadas nas instruções do switch.
MetroidFan2002 22/01/09
9
@ Chris: apenas enumerações de flag devem ser pluralizadas. Ou seja, enumerações cujos membros são combinados usando o | operador.
Kent Boogaart
5
@ Laden: Depende inteiramente do contexto. Uma enumeração de planetas pode ser perfeitamente adequada para um jogo que fornece acesso a um número limitado de planetas. Alterações no código podem ser exatamente o que você deseja se um novo planeta for adicionado ao jogo.
Kent Boogaart
3
@ Richie_W, você pode iterar sobre as enumerações usando a propriedade Values.
Jonathan
23
Uau ... É quase inacreditável ver algo implementado de uma forma mais detalhada maneira em C # que em Java
Sune Rasmussen
218

No C #, você pode definir métodos de extensão nas enumerações, e isso compensa algumas das funcionalidades ausentes.

Você pode definir Planetcomo uma enumeração e também ter métodos de extensão equivalentes a surfaceGravity()e surfaceWeight().

Eu usei atributos personalizados, conforme sugerido por Mikhail , mas o mesmo pode ser alcançado usando um Dicionário.

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
}
finnw
fonte
20
Eu acho que isso deveria ser votado mais. Está mais perto de como as enums em Java funcionam. Eu posso fazer algo como Planet.MERCURY.GetSurfaceGravity () <- Observe o método de extensão em um Enum!
thenonhacker
2
Definitivamente sim. Os métodos de extensão no Enums (heck, métodos de extensão em geral) são uma excelente adição ao C #.
Keiths
3
@AllonGuralnek Thanks. Nem todo mundo concorda com os metadados. Veja o comentário de MattDavey sobre uma questão relacionada com codereview.stackexchange .
finnw
@finnw: Eu nunca ouvi falar do site Code Review SE - obrigado por isso! Eu continuo essa discussão por lá (embora possa merecer sua própria pergunta aqui em Programadores).
Allon Guralnek
esta é uma ótima solução - alguém já testou o desempenho disso? por exemplo, quanto tempo leva para acessar o atributo, comparado ao acesso a uma propriedade de uma classe.
Simon Meyer
35

Em C #, os atributos podem ser usados ​​com enumerações. Um bom exemplo desse padrão de programação com descrição detalhada está aqui (Codeproject)

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

Edit: esta questão foi recentemente perguntada novamente e respondida por Jon Skeet: Qual é o equivalente da enumeração de Java em C #? Classes internas privadas em C # - por que não são usadas com mais frequência?

Edit 2: veja a resposta aceita que amplia essa abordagem de uma maneira muito brilhante!

Mikhail
fonte
1
Agradável! Isso parece um pouco desajeitado, mas, de outro modo, é um método muito aceitável para adicionar dados extras a uma enumeração. Estou francamente surpreso que alguém tenha demorado tanto para mencionar esta ótima solução!
Ogre Psalm33
13

As enumerações Java são na verdade classes completas que podem ter um construtor e métodos particulares, etc. A implementação da IMO Java é muito superior.

Esta página deve ajudá-lo bastante ao aprender c # vindo de um acampamento em java. (O link aponta para as diferenças de enumerações (role para cima / para baixo para outras coisas)

Richard Walton
fonte
1
Embora seu link forneça uma visão geral interessante e abrangente das semelhanças e diferenças entre C # e Java, existem muitos erros no texto (por exemplo, afirma incorretamente que Java protegido é igual a C # interno, enquanto deveria ser protegido interno). Portanto, não levar tudo lá para concedido :)
Mafu
1
Eu não diria que enums de Java são superiores, mesmo se eu sou um fã de java. O C # suporta uma declaração inteira fácil, como a FOO = 0que é mais fácil de usar nas ferramentas ORM (nenhum ordinal()uso propenso a erros é necessário). C # adicional suporta enumerações bit a bit que geralmente são muito úteis, especialmente em combinação com EntityFramework. Java deve estender suas enumerações para permitir que elas também sejam ligadas a números inteiros. Em seguida, eles seriam :) superiores
djmj
4

Algo assim, eu acho:

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

Ou combine as constantes na Planetclasse como acima

Chris S
fonte
8
Não é bem assim - o construtor Planet deve ser privado; parte do ponto de enumeração é que eles são um conjunto fixo de valores. Os valores também seriam definidos na classe Planet também.
22611 Jon Skeet
Ainda não. 1) o enumerador está ausente :) 2) as enumerações nunca devem ser mutáveis. Oh e último, os implora código para uma única classe (esp quando você está tendo um construtor privado)
Nawfal
3

Aqui está outra idéia interessante que atende ao comportamento personalizado disponível em Java. Eu vim com a seguinte Enumerationclasse base:

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

Ele possui um parâmetro de tipo basicamente apenas para que a contagem ordinal funcione corretamente em diferentes enumerações derivadas. O Operatorexemplo de Jon Skeet de sua resposta a outra pergunta (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) acima se torna:

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

Isso dá algumas vantagens.

  • Suporte ordinal
  • Conversão para stringe intque viabiliza declarações de troca
  • GetType () fornecerá o mesmo resultado para cada um dos valores de um tipo de enumeração derivado.
  • Os métodos estáticos de System.Enumpodem ser adicionados à classe de enumeração base para permitir a mesma funcionalidade.
Andrew Cooper
fonte
3

acabamos de fazer uma extensão de enum para c # https://github.com/simonmau/enum_ext

É apenas uma implementação para o typesafeenum, mas funciona muito bem, então criamos um pacote para compartilhar - divirta-se com ele

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)
    {
    }
}
simonmau
fonte
2

Uma enumeração Java é um açúcar sintático para apresentar enumerações de maneira OO. São classes abstratas estendendo a classe Enum em Java, e cada valor de enum é como uma implementação estática de instância pública final da classe enum. Observe as classes geradas e, para um enum "Foo" com 10 valores, você verá as classes "Foo $ 1" a "Foo $ 10" geradas.

Porém, eu não sei C #, só posso especular que um enum nesse idioma é mais como um enum tradicional em idiomas no estilo C. Vejo em uma rápida pesquisa no Google que eles podem conter vários valores, portanto, provavelmente são implementados de maneira semelhante, mas com muito mais restrições do que o compilador Java permite.

JeeBee
fonte
3
Bem, não é tudo sobre Java e C # tudo sobre açúcar sintático para bytecodes da JVM ou CLR? :) Apenas dizendo '
thenonhacker 25/05
2

As enumerações Java permitem conversões fáceis de digitar com segurança do nome usando o método valueOf gerado pelo compilador, ou seja,

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

O equivalente a um enum bruto em C # é mais detalhado:

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

No entanto, se você seguir a rota sugerida por Kent, poderá implementar facilmente um ValueOfmétodo na sua classe enum.

serg10
fonte
O exemplo de Java está usando um método sintético gerado pelo compilador - nada a ver com genéricos. O Enum tem um método valueOf genérico, mas que usa os genéricos de Class e não os de Enum.
Tom Hawtin - tackline
2

Eu suspeito que enums em C # são apenas constantes internas ao CLR, mas não tão familiarizadas com eles. Decompilei algumas classes em Java e posso dizer que você deseja que as Enums sejam convertidas.

Java faz algo sorrateiro. Ele trata a classe enum como uma classe normal, usando, o mais próximo possível, o uso de muitas macros ao referenciar os valores de enum. Se você tiver uma instrução de caso em uma classe Java que usa enumerações, ela substitui as referências de enumeração por números inteiros. Se você precisar ir para a string, ela cria uma matriz de strings indexadas por um ordinal usado em cada classe. Eu suspeito de economizar no boxe.

Se você baixar esse descompilador, verá como ele cria sua classe e o integra. É fascinante ser honesto. Eu não costumava usar a classe enum porque achava que estava inchada por apenas uma matriz de constantes. Eu gosto mais do que a maneira limitada de usá-los em c #.

http://members.fortunecity.com/neshkov/dj.html - Descompilador Java

Paul Bruner
fonte
0

O enum em Java é muito mais complexo que o c # enum e, portanto, mais poderoso. Como é apenas mais um açúcar sintático em tempo de compilação, estou pensando se realmente vale a pena incluir o idioma, dado seu uso limitado em aplicativos da vida real. Às vezes, é mais difícil manter as coisas fora do idioma do que desistir da pressão para incluir um recurso menor.

dmihailescu
fonte
2
Eu respeitosamente discordo. As enums do Java 1.5 são um recurso de linguagem poderoso que eu usei várias vezes para implementar uma solução mais centrada em OO para um problema que lida com um conjunto discreto de itens nomeados constantes.
Ogre Psalm33
1
Pode ser que você fez. Mas, além da integração inteligente da linguagem 'switch', o restante da funcionalidade pode ser facilmente replicado em C # ou Java, como os exemplos acima mostraram.
precisa saber é o seguinte
@dmihailescu "Então o enum em Java é muito mais complexo que o C #. Então eu
larguei o
0
//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);
        }
    }
}
Jim
fonte
0

Você também pode usar uma classe de utilitário para cada tipo de enumeração que contém uma instância com dados avançados para cada valor de enumeração.

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
}
djmj
fonte