Il modo migliore per verificare se un tipo generico è una stringa? (C #)


93

Ho una classe generica che dovrebbe consentire qualsiasi tipo, primitivo o meno. L'unico problema con questo sta usando default(T). Quando chiami default su un tipo di valore o una stringa, lo inizializza su un valore ragionevole (come una stringa vuota). Quando si chiama default(T)un oggetto, restituisce null. Per vari motivi dobbiamo assicurarci che se non è un tipo primitivo, avremo un'istanza predefinita del tipo, non null. Ecco il tentativo 1:

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

Problema: la stringa non è un tipo di valore, ma non ha un costruttore senza parametri. Quindi, la soluzione attuale è:

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

Ma questo sembra un fiasco. C'è un modo migliore per gestire il caso delle stringhe?

Risposte:


161

Tieni presente che il valore predefinito (stringa) è null, non string.Empty. Potresti volere un caso speciale nel tuo codice:

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

2
Pensavo di aver provato quella soluzione prima e non ha funzionato, ma devo aver fatto qualcosa di stupido. E grazie per aver sottolineato che default (stringa) restituisce null, non abbiamo ancora riscontrato un errore a causa di ciò, ma è vero.
Rex M

1
@ Matt Hamilton: +1, ma dovresti aggiornare la tua risposta per restituire '(T) (object) String.Empty' come suggerito da CodeInChaos perché il tipo restituito dal metodo è generico, non puoi semplicemente restituire stringa.
VoodooChild

2
Cosa ne pensi riguardo a is parola chiave? Non è utile qui?
Naveed Butt

Al momento non è possibile applicare l'operatore is con generici e assegnazione o istanza diretta, non è vero ?, sarà una caratteristica interessante
Juan Pablo Garcia Coello

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

Non testato, ma la prima cosa che mi è venuta in mente.


4

È possibile utilizzare l' enumerazione TypeCode . Chiama il metodo GetTypeCode sulle classi che implementano l'interfaccia IConvertible per ottenere il codice del tipo per un'istanza di quella classe. IConvertible è implementato da Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char e String, quindi puoi controllare i tipi primitivi usando questo. Ulteriori informazioni su " Controllo del tipo generico ".


2

Personalmente, mi piace il sovraccarico dei metodi:

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

La discussione per String non funziona qui.

Ho dovuto seguire il codice per i generici per farlo funzionare -

   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
Testare per Stringnome, soprattutto senza considerare uno spazio dei nomi, è sbagliato. E non mi piace neanche il modo in cui converti.
CodesInChaos
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.