2008-08-28 17 views
78

Tengo una clase genérica que debe permitir cualquier tipo, primitivo o de otro tipo. El único problema con esto es usar default(T). Cuando llama por defecto a un tipo de valor o una cadena, lo inicializa a un valor razonable (como una cadena vacía). Cuando llama al default(T) en un objeto, devuelve null. Por diversas razones, debemos asegurarnos de que si no es un tipo primitivo, tendremos una instancia predeterminada del tipo, , no nulo. Aquí es el intento 1:¿La mejor manera de probar si un tipo genérico es una cadena? (C#)

T createDefault() 
{ 
    if(typeof(T).IsValueType) 
    { 
     return default(T); 
    } 
    else 
    { 
     return Activator.CreateInstance<T>(); 
    } 
} 

Problema - cadena no es un tipo de valor, pero no tiene un constructor sin parámetros. Entonces, la solución actual es:

T createDefault() 
{ 
    if(typeof(T).IsValueType || typeof(T).FullName == "System.String") 
    { 
     return default(T); 
    } 
    else 
    { 
     return Activator.CreateInstance<T>(); 
    } 
} 

Pero esto se siente como un error. ¿Hay alguna manera más agradable de manejar la caja de cuerdas?

Respuesta

133

Tenga en cuenta que el valor predeterminado (cadena) es nulo, no de cadena. Vacío. Es posible que desee un caso especial en el código:

if (typeof(T) == typeof(String)) return (T)(object)String.Empty; 
+2

pensé Probé esa solución antes y no funcionó, pero debo haber hecho algo estúpido. Y gracias por señalar que el valor por defecto (cadena) arroja un valor nulo, todavía no hemos encontrado un error debido a eso, pero eso es cierto. –

+1

@Matt Hamilton: +1, pero debe actualizar su respuesta para devolver '(T) (objeto) String.Empty' como lo sugiere CodeInChaos porque el tipo de devolución del método es genérico, no puede simplemente devolver una cadena. – VoodooChild

+2

¿Qué pasa con la palabra clave 'is'? ¿No es de utilidad aquí? –

13
if (typeof(T).IsValueType || typeof(T) == typeof(String)) 
{ 
    return default(T); 
} 
else 
{ 
    return Activator.CreateInstance<T>(); 
} 

No probado, pero lo primero que se le vino a la mente.

4

Usted puede utilizar la enumeración TypeCode. Llame al método GetTypeCode en las clases que implementan la interfaz IConvertible para obtener el código de tipo para una instancia de esa clase. IConvertible es implementado por Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Simple, Doble, Decimal, DateTime, Char y String, por lo que puede verificar los tipos primitivos usando esto. Más información sobre "Generic Type Checking".

-6

La discusión para String no está funcionando aquí.

que tenía que tener siguiente código para los genéricos para que funcione -

private T createDefault() 
    { 

     {  
      if(typeof(T).IsValueType)  
      {   
       return default(T);  
      } 
      else if (typeof(T).Name == "String") 
      { 
       return (T)Convert.ChangeType(String.Empty,typeof(T)); 
      } 
      else 
      { 
       return Activator.CreateInstance<T>(); 
      } 
     } 

    } 
+3

La prueba de 'Cadena' por su nombre, especialmente sin tener en cuenta un espacio de nombres es malo. Y tampoco me gusta la forma en que conviertes. – CodesInChaos

+0

-1 Esta ecualización no es correcta – IamStalker

2

Personalmente, me gusta la sobrecarga de métodos:

public static class Extensions { 
    public static String Blank(this String me) {  
    return String.Empty; 
    } 
    public static T Blank<T>(this T me) {  
    var tot = typeof(T); 
    return tot.IsValueType 
     ? default(T) 
     : (T)Activator.CreateInstance(tot) 
     ; 
    } 
} 
class Program { 
    static void Main(string[] args) { 
    Object o = null; 
    String s = null; 
    int i = 6; 
    Console.WriteLine(o.Blank()); //"System.Object" 
    Console.WriteLine(s.Blank()); //"" 
    Console.WriteLine(i.Blank()); //"0" 
    Console.ReadKey(); 
    } 
} 
Cuestiones relacionadas