2008-08-28 3 views
78

Ich habe eine generische Klasse, die jeden Typ, primitiv oder anders, erlauben sollte. Das einzige Problem dabei ist die Verwendung von . Wenn Sie den Standardwert für einen Werttyp oder eine Zeichenfolge aufrufen, initialisiert er diese auf einen sinnvollen Wert (z. B. eine leere Zeichenfolge). Wenn Sie default(T) für ein Objekt aufrufen, gibt es null zurück. Aus verschiedenen Gründen müssen wir sicherstellen, dass, wenn es sich nicht um einen primitiven Typ handelt, eine Standardinstanz des Typs nicht null ist. Hier ist der Versuch 1:Der beste Weg zu testen, ob ein generischer Typ eine Zeichenkette ist? (C#)

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

Problem - Zeichenfolge ist kein Werttyp, aber es hat nicht einen parameterlosen Konstruktor haben. Die aktuelle Lösung ist also:

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

Aber das fühlt sich an wie ein Klodge. Gibt es eine schönere Möglichkeit, mit dem String Case umzugehen?

Antwort

133

Beachten Sie, dass der Standardwert (string) null ist, nicht string.Empty. Sie können einen Sonderfall in Ihrem Code wollen:

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

Ich dachte, ich früher diese Lösung versucht und es hat nicht funktioniert, aber ich muss etwas Dummes getan haben. Und danke, dass Sie darauf hingewiesen haben, dass der Standardwert (string) null zurückgibt, wir haben deswegen noch keinen Fehler gefunden, aber das stimmt. –

+1

@Matt Hamilton: +1, aber Sie sollten Ihre Antwort aktualisieren, um '(T) (object) String.Empty' zurückzugeben, wie von CodeInChaos vorgeschlagen, da der Rückgabetyp der Methode generisch ist, können Sie nicht einfach einen String zurückgeben. – VoodooChild

+2

Was ist mit dem Schlüsselwort "is"? Ist das nicht von Nutzen? –

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

Nicht getestet, aber die erste Sache, die in den Sinn kam.

4

Sie die TypeCode Aufzählung verwenden können. Rufen Sie die GetTypeCode-Methode für Klassen auf, die die IConvertible-Schnittstelle implementieren, um den Typcode für eine Instanz dieser Klasse abzurufen. IConvertible wird von Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Dezimal, DateTime, Char und String implementiert, so dass Sie nach primitiven Typen suchen können. Weitere Informationen zu "Generic Type Checking".

-6

Die Diskussion für String funktioniert hier nicht.

hatte ich folgenden Code haben für Generika es funktioniert -

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

Testen auf 'String' nach Namen, besonders ohne auf einen Namespace zu achten ist schlecht. Und ich mag auch nicht die Art, wie Sie konvertieren. – CodesInChaos

+0

-1 Dies ist nicht korrekt ausgleichend – IamStalker

2

Ich persönlich mag Methode Überlastung:

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