2008-11-09 14 views
53

En vs2008, es posible escribir un método de extensión que se aplicaría a cualquier enumeración.Métodos de extensión de enumeración

Sé que puede escribir métodos de extensión en una enumeración específica, pero quiero poder realizar todas las enumeraciones con un solo método de extensión. es posible?

Respuesta

80

Sí, solo código en la base Enum tipo, p. Ej.

public static void Something(this Enum e) 
{ 
    // code here 
} 

El lado negativo es que probablemente va a terminar haciendo algunas cosas bastante desagradable como encontrar el tipo de base real usando Enum.GetUnderlyingType, fundición, y bajando diferentes ramas dependiendo de qué tipo de base de la enumeración es, pero puede encontrar algunos buenos usos (por ejemplo, tenemos IsOneOf y IsCombinationOf métodos que se aplican a todas las enumeraciones).

PD: Recuerde que al escribir el método que, aunque desaconsejable, puede usar float y double como tipos de base para enumeraciones, por lo que necesitará algunos casos especiales para aquellos, así como valores sin firmar.

+0

Los ejemplos que diste son exactamente lo que yo quiero hacer, incluso el mismo nombre. :) –

+4

@Greg: ¿En qué idioma puede usar float y double como el tipo subyacente de una enumeración? No puede en C# - obtiene el error CS1008: escriba byte, sbyte, short, ushort, int, uint, long o ulong expected –

+3

El único lenguaje que conozco que lo admite es CIL. En realidad no lo he probado para probarlo porque parece una idea generalmente mala, pero vea el comentario de Rico cerca de la parte inferior aquí: http://en.csharp-online.net/.NET_Type_Design_Guidelines%E2%80%94Enum_Design –

18

Sí, puedes. El tipo de extensión de destino es del tipo Enum. En C#, esto se haría como:

public static void EnumExtension(this Enum e) 
{ 
} 

o así en VB:

<Extension()> _ 
Public Sub EnumExtension(ByVal s As Enum) 
End Sub 
18

FYI Aquí es un gran ejemplo de un método de enumeración de extensión que he podido utilizar. Implementa una función sensitiva a TryParse() para enumeraciones:

public static class ExtensionMethods 
{ 
    public static bool TryParse<T>(this Enum theEnum, string strType, 
     out T result) 
    { 
     string strTypeFixed = strType.Replace(' ', '_'); 
     if (Enum.IsDefined(typeof(T), strTypeFixed)) 
     { 
      result = (T)Enum.Parse(typeof(T), strTypeFixed, true); 
      return true; 
     } 
     else 
     { 
      foreach (string value in Enum.GetNames(typeof(T))) 
      { 
       if (value.Equals(strTypeFixed, 
        StringComparison.OrdinalIgnoreCase)) 
       { 
        result = (T)Enum.Parse(typeof(T), value); 
        return true; 
       } 
      } 
      result = default(T); 
      return false; 
     } 
    } 
} 

que usaría de la siguiente manera:

public enum TestEnum 
{ 
    A, 
    B, 
    C 
} 

public void TestMethod(string StringOfEnum) 
{ 
    TestEnum myEnum; 
    myEnum.TryParse(StringOfEnum, out myEnum); 
} 

Éstos son los dos sitios que he visitado para ayudar a llegar a este código :

Case Insensitive TryParse for Enums

Extension methods for Enums

+8

Al igual que una nota al pie, desde .net 4 en adelante hay Enum.TryParse toma una sobrecarga para especificar la distinción entre mayúsculas y minúsculas: http://msdn.microsoft.com/en-us/ library/dd991317% 28v = vs.100% 29.aspx – KevD

9

Aquí hay otro ejemplo: también mejor en mi humilde opinión que tener que crear e inicializar una variable de temperatura.

public static class ExtensionMethods 
{ 
    public static void ForEach(this Enum enumType, Action<Enum> action) 
    { 
     foreach (var type in Enum.GetValues(enumType.GetType())) 
     { 
      action((Enum)type); 
     } 
    } 
} 

public enum TestEnum { A,B,C } 
public void TestMethod() 
{ 
    default(TestEnum).ForEach(Console.WriteLine); 
} 
+0

Aún está creando una instancia temporal de la enumeración en 'default (TestEnum)', aunque una que es anónima e inmediatamente activa para la recolección de elementos no utilizados. Vale la pena señalar que los métodos de extensión simplemente no funcionan sin una instancia de lo que se está extendiendo, por lo que lo más cercano que podemos obtener es crear una instancia del Tipo de la enumeración en sí y tener un método de extensión de ese tipo. Consulte http://stackoverflow.com/questions/2422113/extension-method-on-enumeration-not-instance-of-enumeration para obtener una forma interesante de lograr esto. – MushinNoShin

4

También puede aplicar el método de conversión de la siguiente manera:

public static class Extensions 
{ 
    public static ConvertType Convert<ConvertType>(this Enum e) 
    { 
     object o = null; 
     Type type = typeof(ConvertType); 

     if (type == typeof(int)) 
     { 
      o = Convert.ToInt32(e); 
     } 
     else if (type == typeof(long)) 
     { 
      o = Convert.ToInt64(e); 
     } 
     else if (type == typeof(short)) 
     { 
      o = Convert.ToInt16(e); 
     } 
     else 
     { 
      o = Convert.ToString(e); 
     } 

     return (ConvertType)o; 
    } 
} 

Aquí es un ejemplo de uso:

int a = MyEnum.A.Convert<int>(); 
+0

Creo que cada 'Enum' implementa' IConvertible' de todos modos. – ja72

2

A veces hay una necesidad de convertir de una enumeración a otro, basado en el nombre o valor de la enumeración. Así es cómo se puede hacer muy bien con los métodos de extensión:

enum Enum1 { One = 1, Two = 2, Three = 3 }; 
enum Enum2 { Due = 2, Uno = 1 }; 
enum Enum3 { Two, One }; 

Enum2 e2 = Enum1.One.ConvertByValue<Enum2>(); 
Enum3 e3 = Enum1.One.ConvertByName<Enum3>(); 
Enum3 x2 = Enum1.Three.ConvertByValue<Enum3>(); 

public static class EnumConversionExtensions 
{ 
    public static T ConvertByName<T>(this Enum value) 
    { 
     return (T)Enum.Parse(typeof(T), Enum.GetName(value.GetType(), value)); 
    } 

    public static T ConvertByValue<T>(this Enum value) 
    { 
     return (T)((dynamic)((int)((object)value))); 
    } 
} 
1

Otro ejemplo de hacer extensión Enum - pero esta vez se devuelve el tipo de enumeración de entrada.

public static IEnumerable<T> toElementsCollection<T>(this T value) where T : struct, IConvertible 
    { 
     if (typeof(T).IsEnum == false) throw new Exception("typeof(T).IsEnum == false"); 

     return Enum.GetValues(typeof(T)).Cast<T>(); 
    } 

Ejemplo de uso:

public enum TestEnum { A,B,C }; 

TestEnum.A.toElementsCollection(); 
Cuestiones relacionadas