tutorial - c# get number of enum




C#vs Java Enum(per quelli nuovi di C#) (8)

È anche possibile utilizzare una classe di utilità per ogni tipo di enum che contiene un'istanza con dati avanzati per ciascun valore enum.

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
}

Ho programmato in Java per un po 'e sono stato gettato su un progetto interamente scritto in C #. Sto cercando di arrivare alla velocità in C #, e ho notato enum utilizzati in diversi punti del mio nuovo progetto, ma a prima vista, le enumerazioni di C # sembrano essere più semplici dell'implementazione di Java 1.5+. Qualcuno può enumerare le differenze tra C # e le enumerazioni Java e come superare le differenze? (Non voglio iniziare una guerra di lingue, voglio solo sapere come fare alcune cose in C # che facevo in Java). Per esempio, qualcuno potrebbe pubblicare una controparte in C # del famoso esempio di enum Planet di 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 ...]

Ecco un'altra idea interessante che soddisfa il comportamento personalizzato disponibile in Java. Ho trovato la seguente classe di base 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; }
    }
}

Ha un parametro di tipo praticamente solo così il conteggio ordinale funzionerà correttamente tra le diverse enumerazioni derivate. L'esempio di Operator Jon Skeet dalla sua risposta ad un'altra domanda (http://.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) sopra diventa:

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

Questo offre alcuni vantaggi.

  • Supporto ordinale
  • Conversione in string e int che rende fattibili le istruzioni switch
  • GetType () darà lo stesso risultato per ciascuno dei valori di un tipo di Enumerazione derivato.
  • I metodi statici di System.Enum possono essere aggiunti alla classe di enumerazione di base per consentire la stessa funzionalità.

In C # gli attributi possono essere usati con le enumerazioni. Un buon esempio di questo modello di programmazione con descrizione dettagliata è here (Codeproject)

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

Modifica: questa domanda è stata recentemente chiesta di nuovo e ha risposto Jon Skeet: Qual è l'equivalente dell'enum di Java in C #? Classi private interne in C # - perché non vengono usate più spesso?

Modifica 2: vedi la risposta accettata che estende questo approccio in modo molto brillante!


L'enum in Java è molto più complesso dell'enum C # e quindi più potente. Dato che si tratta solo di un altro zucchero sintattico in fase di compilazione, mi chiedo se valga davvero la pena di includere il linguaggio dato il suo uso limitato nelle applicazioni reali. A volte è più difficile mantenere le cose fuori dalla lingua piuttosto che abbandonare la pressione per includere una caratteristica minore.



Le enumerazioni nel CLR sono semplicemente costanti con nome. Il tipo sottostante deve essere integrale. In Java un'enumerazione è più simile a un'istanza denominata di un tipo. Quel tipo può essere piuttosto complesso e - come mostra il tuo esempio - contiene più campi di vario tipo.

Per portare l'esempio in C # vorrei semplicemente cambiare l'enum in una classe immutabile ed esporre istanze statiche readonly di quella classe:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Planet pEarth = Planet.MERCURY;
            double earthRadius = pEarth.Radius; // Just threw it in to show usage

            double earthWeight = double.Parse("123");
            double mass = earthWeight / pEarth.SurfaceGravity();
            foreach (Planet p in Planet.Values)
                Console.WriteLine("Your weight on {0} is {1}", p, 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;
            }
        }

        private readonly string name;
        private readonly double mass;   // in kilograms
        private readonly double radius; // in meters

        Planet(string name, double mass, double radius)
        {
            this.name = name;
            this.mass = mass;
            this.radius = radius;
        }

        public string Name { get { return name; } }

        public double Mass { get { return mass; } }

        public double Radius { get { return radius; } }

        // universal gravitational constant  (m3 kg-1 s-2)
        public const double G = 6.67300E-11;

        public double SurfaceGravity()
        {
            return G * mass / (radius * radius);
        }

        public double SurfaceWeight(double otherMass)
        {
            return otherMass * SurfaceGravity();
        }

        public override string ToString()
        {
            return name;
        }
    }
}

Sospetto che le enumerazioni in C # siano solo costanti interne al CLR, ma non che siano familiari con loro. Ho decompilato alcune classi in Java e posso dirti che gli Enums sono una volta che converti.

Java fa qualcosa di nascosto. Tratta la classe enum come una classe normale con, il più vicino possibile, usando un sacco di macro quando si fa riferimento ai valori enum. Se si dispone di un'istruzione case in una classe Java che utilizza enumerazione, sostituisce i riferimenti enum agli interi. Se devi andare alla stringa, crea una serie di stringhe indicizzate da un ordinale che usa in ogni classe. Sospetto di risparmiare sul pugilato.

Se scarichi questo decompilatore, vedrai come crea la sua classe e lo integra. Piuttosto affascinante per essere onesti. Non usavo la classe enum perché pensavo che fosse troppo gonfio solo per una serie di costanti. Mi piace meglio del modo limitato in cui puoi usarli in C #.

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


Un enum di Java è zucchero sintattico per presentare enumerazioni in modo OO. Sono classi astratte che estendono la classe Enum in Java e ogni valore enum è come un'implementazione di istanza pubblica finale statica della classe enum. Guarda le classi generate, e per un enum "Foo" con 10 valori, vedrai "Foo $ 1" attraverso le classi "Foo $ 10" generate.

Non conosco C #, ma posso solo supporre che un enum in quella lingua sia più simile a un enum tradizionale nei linguaggi in stile C. Da una rapida ricerca su Google, tuttavia, è possibile che siano in grado di contenere più valori, pertanto sono probabilmente implementati in modo simile, ma con molte più restrizioni rispetto a quanto consentito dal compilatore Java.





language-comparisons