Melhor maneira de testar se um tipo genérico é uma string? (C #)


93

Tenho uma classe genérica que deve permitir qualquer tipo, primitivo ou não. O único problema com isso é usar default(T). Quando você chama default em um tipo de valor ou string, ele o inicializa com um valor razoável (como string vazia). Quando você chama default(T)um objeto, ele retorna nulo. Por vários motivos, precisamos garantir que, se não for um tipo primitivo, teremos uma instância padrão do tipo, não nula. Aqui está a tentativa 1:

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

Problema - string não é um tipo de valor, mas não tem um construtor sem parâmetros. Portanto, a solução atual é:

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

Mas isso parece um desastre. Existe uma maneira mais agradável de lidar com o caso da string?

Respostas:


161

Lembre-se de que o padrão (string) é nulo, não string.Empty. Você pode querer um caso especial em seu código:

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

2
Pensei ter tentado essa solução antes e não funcionou, mas devo ter feito algo estúpido. E obrigado por apontar que default (string) retorna nulo, não encontramos um erro ainda por causa disso, mas é verdade.
Rex M

1
@Matt Hamilton: +1, mas você deve atualizar sua resposta para retornar '(T) (objeto) String.Empty' como sugerido por CodeInChaos porque o tipo de retorno do método é genérico, você não pode apenas retornar string.
VoodooChild

2
E quanto à ispalavra - chave? Isso não é útil aqui?
Naveed Butt

No momento não é possível aplicar o operador is com genéricos e atribuição ou instanciação direta, não é ?, será um recurso legal
Juan Pablo Garcia Coello

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

Não testado, mas a primeira coisa que me veio à mente.


4

Você pode usar a enumeração TypeCode . Chame o método GetTypeCode em classes que implementam a interface IConvertible para obter o código de tipo para uma instância dessa classe. IConvertible é implementado por Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char e String, então você pode verificar por tipos primitivos usando isso. Mais informações sobre " Verificação de tipo genérico ".


2

Pessoalmente, gosto de sobrecarga de método:

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


-6

A discussão sobre String não está funcionando aqui.

Eu precisava seguir o código de genéricos para fazê-lo funcionar -

   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
Testar Stringpor nome, especialmente sem considerar um namespace, é ruim. E também não gosto da maneira como você se converte.
CodesInChaos
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.