2009-09-03 4 views
24

¿Cuál es el equivalente de la enumeración de Java en C#?¿Cuál es el equivalente de la enumeración de Java en C#?

+2

tal vez soy más de pensarlo, pero no tengo esperan que ya sabe acerca de enumeración C# 's y hay una cierta funcionalidad con enumeración de Java, que se está refiriendo. Si es así, quizás podrías elaborar en tu pregunta. –

+8

Esta pregunta es perfectamente clara si usted sabe algo acerca de Java 'enum's. –

+0

@Yishai - En C# enumera por defecto a Int32, pero se puede cambiar cualquier tipo numérico –

Respuesta

34

La funcionalidad completa de enum de Java no está disponible en C#. Puede venir razonablemente cerrar usando tipos anidados y un constructor privado sin embargo. Por ejemplo:

using System; 
using System.Collections.Generic; 
using System.Xml.Linq; 

public abstract class Operator 
{ 
    public static readonly Operator Plus = new PlusOperator(); 
    public static readonly Operator Minus = 
     new GenericOperator((x, y) => x - y); 
    public static readonly Operator Times = 
     new GenericOperator((x, y) => x * y); 
    public static readonly Operator Divide = 
     new GenericOperator((x, y) => x/y); 

    // Prevent other top-level types from instantiating 
    private Operator() 
    { 
    } 

    public abstract int Execute(int left, int right); 

    private class PlusOperator : Operator 
    { 
     public override int Execute(int left, int right) 
     { 
      return left + right; 
     } 
    } 

    private class GenericOperator : Operator 
    { 
     private readonly Func<int, int, int> op; 

     internal GenericOperator(Func<int, int, int> op) 
     { 
      this.op = op; 
     } 

     public override int Execute(int left, int right) 
     { 
      return op(left, right); 
     } 
    } 
} 

Por supuesto que no lo tienen utilizar tipos anidados, pero dar el "comportamiento personalizado" parte útil que las enumeraciones de Java son agradables para. En otros casos, puede pasar argumentos a un constructor privado para obtener un conjunto restringido de valores conocidos.

Un par de cosas que no le da:

  • apoyo ordinal
  • apoyo Interruptor
  • EnumSet
  • serialización/deserialización (como un conjunto unitario)

Algunos de eso probablemente podría hacerse con suficiente esfuerzo, aunque el cambio no sería factible sin hackers. Ahora bien, si el lenguaje hiciera algo como esto, podría hacer cosas interesantes para hacer que el conmutador funcione haciendo que el hackeo sea automático (por ejemplo, declarando una carga de const campos automáticamente, y cambiando cualquier conmutación sobre el tipo de enumeración por un entero entero permitiendo casos "conocidos")

Ah, y los tipos parciales significan que no tiene que tener todos de los valores enum en el mismo archivo. Si cada valor se involucró bastante (lo cual es definitivamente posible) cada uno podría tener su propio archivo.

+0

Creo que sería trivial admitir instrucciones de conmutación (y ordinales) utilizando una conversión implícita a int, ¿verdad? ¿Qué pasé por alto? –

+2

@LimitedAtonement: ¿Cómo representaría los valores * constantes * que necesitaría para las expresiones de casos? –

+0

Leí su artículo recientemente sobre algunas veces cuando los campos no privados están justificados. ¿Es este uno de esos momentos? –

-1

enum, o necesita algo en particular que las enumeraciones Java tienen pero C# no?

+0

En Java, las enumeraciones pueden tener múltiples valores asociados para cada enumeración, métodos con lógica y constructores. Al menos a partir de C# 3.0, las enumeraciones de C# siguen siendo solo una lista de constantes, con un posible valor asociado. –

+6

-1: las enumeraciones de Java son * así que * mucho más poderosas que las de C#. – Kramii

+0

+1 para contrarrestar el -1 de Kramii. Las enumeraciones de C# pueden tener métodos de extensión que compensa la ausencia de algunas de esas características. – finnw

17

Las enumeraciones son una de las pocas características del lenguaje que se implementa mejor en Java que C#. En Java, las enumeraciones son instancias nombradas completas de un tipo, mientras que las enumeraciones C# son básicamente constantes.

Dicho esto, para el caso básico, se verán similares. Sin embargo, en java, usted tiene más poder, ya que puede agregar comportamiento a las enumeraciones individuales, ya que son clases completas.

¿Hay alguna característica en particular que usted esté buscando?

+8

"Funcionarán igual", no IMO, porque los números constantes no pueden tener un * comportamiento * personalizado, a diferencia de los valores enum de Java. –

+2

yup, de ahí la calificación 'para uso básico'. Estoy de acuerdo en que una de las cosas buenas de Java enums es el comportamiento personalizado – Chi

+1

Me gustan los Java Enums que los C# Enums. Con C# Enums, difunde un gran número de Oídos de Conversión de Conmutador, y muchos de estos códigos dispersos en las declaraciones de interruptor podrían haber sido colocados como métodos asociados con cada Enum. – thenonhacker

4

Probablemente puedas usar el viejo modelo de enum en tipo seguro que utilizamos en Java antes de obtener los reales (suponiendo que los que están en C# realmente no son clases como afirma un comentario). El patrón se describe justo antes del medio de this page

+0

+1: un enfoque que uso. – Kramii

5

Aquí hay otra idea interesante. Se me ocurrió la siguiente clase Enumeration de 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; } 
    } 
} 

Tiene un parámetro de tipo básicamente sólo por lo que el recuento ordinal funcionará adecuadamente a través de diferentes enumeraciones derivados.Operator ejemplo de Jon anterior se convierte en:

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

Esto da algunas ventajas.

  • apoyo ordinal
  • Conversión a string y int que hace sentencias switch factibles
  • GetType() dará el mismo resultado para cada uno de los valores de un tipo de enumeración derivada.
  • Los métodos estáticos de System.Enum se pueden agregar a la clase base Enumeration para permitir la misma funcionalidad.
+0

Estoy haciendo algo de conversión de Java a C#, así que miré tu respuesta hace un mes y pensé 'demasiado para mis necesidades' ... Ahora estoy de vuelta, viendo mucho más valor, ya que necesito la funcionalidad 'recuperar enum por (cadena) nombre'. ¡Prestigio! –

+0

@Andrew Cooper, re: "Esto ofrece algunas ventajas. * Soporte ordinario * Conversión a cadena e int que hace que las declaraciones de conmutación sean factibles" - parece que esto todavía no da soporte a la instrucción switch, ya que el compilador se queja de que las sentencias de caso necesitan un valor constante . No acepta ni (int) cast ni .Ordinal value como const. – tomosius

1
//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); 
     } 
    } 
} 
Cuestiones relacionadas