Der beste Weg, um zu testen, ob ein generischer Typ eine Zeichenfolge ist? (C #)


93

Ich habe eine generische Klasse, die jeden Typ zulassen sollte, primitiv oder auf andere Weise. Das einzige Problem dabei ist die Verwendung default(T). Wenn Sie für einen Werttyp oder eine Zeichenfolge die Standardeinstellung aufrufen, wird diese auf einen angemessenen Wert (z. B. eine leere Zeichenfolge) initialisiert. Wenn Sie default(T)ein Objekt aufrufen , wird null zurückgegeben. Aus verschiedenen Gründen müssen wir sicherstellen, dass wir eine Standardinstanz des Typs haben, die nicht null ist, wenn es sich nicht um einen primitiven Typ handelt . Hier ist Versuch 1:

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

Problem - Zeichenfolge ist kein Werttyp, hat jedoch keinen parameterlosen Konstruktor. Die aktuelle Lösung lautet 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 Kludge. Gibt es eine schönere Möglichkeit, mit dem String-Fall umzugehen?

Antworten:


160

Beachten Sie, dass der Standardwert (Zeichenfolge) null und nicht string.Empty ist. Möglicherweise möchten Sie einen Sonderfall in Ihrem Code:

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

2
Ich dachte, ich hätte diese Lösung früher ausprobiert und sie hat nicht funktioniert, aber ich muss etwas Dummes getan haben. Und danke, dass Sie darauf hingewiesen haben, dass default (string) null zurückgibt. Wir sind deshalb noch nicht auf einen Fehler gestoßen, aber das ist wahr.
Rex M

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

2
Was ist mit dem isSchlüsselwort? Ist das hier nicht von Nutzen?
Naveed Butt

Im Moment ist es nicht möglich, den is-Operator mit Generika und Zuordnung oder direkter Instanzierung anzuwenden, nicht wahr? Wird eine coole Funktion sein
Juan Pablo Garcia Coello

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

Ungetestet, aber das erste, was mir in den Sinn kam.


4

Sie können die TypeCode- Aufzählung verwenden. 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, Decimal, DateTime, Char und String implementiert, sodass Sie damit nach primitiven Typen suchen können. Weitere Informationen zu " Generic Type Checking ".


2

Persönlich mag ich Methodenüberladung:

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

Die Diskussion für String funktioniert hier nicht.

Ich musste folgenden Code für Generika haben, damit 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
Das Testen nach StringNamen, insbesondere ohne Berücksichtigung eines Namespace, ist schlecht. Und ich mag es auch nicht, wie du konvertierst.
CodesInChaos
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.