¿La mejor manera de probar si un tipo genérico es una cadena? (C#)

93

Tengo una clase genérica que debería permitir cualquier tipo, primitivo o no. El único problema con esto es usar default(T). Cuando llama a default en un tipo de valor o una cadena, lo inicializa a un valor razonable (como una cadena vacía). Cuando llama default(T)a un objeto, devuelve nulo. Por varias razones, necesitamos asegurarnos de que si no es un tipo primitivo, entonces tendremos una instancia predeterminada del tipo, no nula. Aquí está el intento 1:

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

Problema: la 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 una torpeza. ¿Existe una forma mejor de manejar el caso de cuerdas?

Rex M
fuente

Respuestas:

161

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

if (typeof(T) == typeof(String)) return (T)(object)String.Empty;
Matt Hamilton
fuente
2
Pensé que probé esa solución antes y no funcionó, pero debo haber hecho algo estúpido. Y gracias por señalar que el valor predeterminado (cadena) devuelve nulo, todavía no nos encontramos con un error debido a eso, pero eso es cierto.
Rex M
1
@Matt Hamilton: +1, pero debe actualizar su respuesta para devolver '(T) (objeto) String.Empty' como lo sugiere CodeInChaos porque el tipo de retorno del método es genérico, no puede simplemente devolver una cadena.
VoodooChild
2
¿Qué pasa con la ispalabra clave? ¿No es útil aquí?
Naveed Butt
Por el momento no es posible aplicar el operador is con genéricos y asignación o instanciación directa, ¿no ?, será una característica interesante
Juan Pablo García Coello
14
if (typeof(T).IsValueType || typeof(T) == typeof(String))
{
     return default(T);
}
else
{
     return Activator.CreateInstance<T>();
}

Sin probar, pero lo primero que me vino a la mente.

FlySwat
fuente
4

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 está implementado por Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char y String, por lo que puede verificar los tipos primitivos usando esto. Más información sobre " Verificación de tipo genérico ".

jfs
fuente
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();
  }
}
theoski
fuente
-6

La discusión sobre String no funciona aquí.

Tenía que tener el siguiente código para genéricos para que funcionara:

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

    }
Añil
fuente
3
Probar Stringpor nombre, especialmente sin tener en cuenta un espacio de nombres, es malo. Y tampoco me gusta la forma en que te conviertes.
CodesInChaos