2015-05-14 9 views
5

Ich versuche, die folgende Methode mit Generics zu schreiben. (Meine eigentliche Methode ist komplexer als das.)NULL-Wert für unbekannten Typ zurückgeben

public T ParseDictionaryItem<T>(string s, Dictionary<string, T> dictionary) 
{ 
    T result; 
    if (dictionary.TryGetValue(s, out result)) 
     return result; 
    // TODO: Return special value such as null to indicate invalid item 
} 

Mein Ziel ist es so etwas wie null zurück, wenn das Element nicht im Wörterbuch enthalten ist. Das Problem ist, dass ich nicht weiß, welcher Typ T ist. Wenn T zum Beispiel eine ganze Zahl wäre, dann sollte ich den Typ T? zurückgeben. Wenn T jedoch eine Klasse ist, ist sie bereits nullfähig. Und ich werde das bis zur Laufzeit nicht wissen.

Kann jemand einen sauberen Weg sehen, einen speziellen Wert in dieser Methode zurückzugeben, um anzuzeigen, dass der Artikel ungültig ist? Ich bin offen für etwas anderes als null, aber es muss ein besonderer Wert sein. (0 ist kein besonderer Wert für ganze Zahlen.)

+0

Das Beste, was Sie tun können, ist 'default (T)', aber das ist nicht "einzigartig" für ein "int". –

+1

Am einfachsten erstellen Sie zwei Überladungen - eine für Klassentypen und eine für Nullable-Strukturen. Alternativ können Sie auch Ihren eigenen 'Maybe ' Typ erstellen und diesen zurückgeben. – Lee

+1

Warum verwendet der Anrufer TryGetValue nicht direkt? Es gibt ein bool zurück, das angibt, ob das Element gültig ist und ein out-Parameter das Element hat, sofern es gültig ist. Oder wenn die Methode komplizierter ist, zumindest etwas, das diesem Muster folgt. –

Antwort

10

würde ich vorschlagen, eine ParseResult<T> Rückkehr, die als so etwas wie definiert:

public struct ParseResult<T> 
{ 
    // Or an exception, or a way of creating an exception 
    private readonly bool success; 
    private readonly T value; 

    // Accessors etc 
} 

Auf diese Weise müssen Sie über NULL-Zulässigkeit keine Sorge, und Sie kann es machen sehr klar, was Sie tun. Dies ist das Muster, das ich in Noda Time verwendet habe und meiner Meinung nach hat es sehr gut funktioniert. (Zur Zeit verwenden wir eine Klasse anstatt einer Struktur, aber ich könnte das ändern ...)

Ich ziehe es andere Ansätze, weil:

  • Es ist sauber zu nennen, im Gegensatz zu mit einem out Parameter
  • Es muss nicht hässlich und möglicherweise teuer try/catch
  • Es genau die gleiche Art und Weise verhält Handhabung ob T eine Art Referenz oder ein Werttyp
  • Es ist flexibel en ough die Situation dar, in dem null ein erfolgreicher Parse-Wert
  • Sie propagieren können noch ohne werfen die Ausnahme, die Ursache eines Fehlers ist, wenn Sie zu
  • brauchen nicht
+0

Danke, ich habe darüber nachgedacht, eine Klasse mit zusätzlichen Informationen zurückzugeben, habe aber auf etwas leichteres und einfacheres gehofft. Aber vielleicht ist das der beste Ansatz. –

+0

Ich benutze dieses Muster mehr und mehr. – Matthew

+1

Wenn nur 'Nullable' nicht die Einschränkung hat, dass das generische Argument ein Werttyp ist ... – Servy

4

Sie zwei Methoden erstellen kann man für Werttypen und ein anderer für den Referenztyp. Werttypmethode gibt T? anstelle von T zurück. In beiden Methoden können Sie null zurückgeben, um einen ungültigen Wert anzugeben.

public T? ParseDictionaryItemValueType<T>(string s, Dictionary<string, T> dictionary) 
where T : struct 
{ 
    T result; 
    if (dictionary.TryGetValue(s, out result)) 
     return result; 
    return null; 
} 

public T ParseDictionaryItemReferenceType<T>(string s, Dictionary<string, T> dictionary) 
where T : class 
{ 
    T result; 
    dictionary.TryGetValue(s, out result); 
    return result; 
} 
5

Vielleicht zwei Überlastungen würde helfen:

public T? ParseStructDictionaryItem<T>(string s, Dictionary<string, T> dictionary) where T : struct 
{ 
    T result; 
    if (dictionary.TryGetValue(s, out result)) 
     return result; 
    return null; 
} 

public T ParseReferenceDictionaryItem<T>(string s, Dictionary<string, T> dictionary) where T : class 
{ 
    T result; 
    if (dictionary.TryGetValue(s, out result)) 
     return result; 
    return default(T); 
} 
+0

@AnthonyPegram Ich weiß, sie haben andere Namen. –

+0

Sorry, hatte gerade das bemerkt. Vorgehen. –

0

Warum das Rad neu erfinden? Werfen Sie einen Blick auf Ihren eigenen Code:
Sie verwenden die TryGetValue Methode des Wörterbuchs. Wie geht es mit dem gleichen Problem?
Ich schlage vor, Sie folgen den Spuren der.Net Framework-Entwickler und das Gleiche tun:

public bool TryParseDictionaryItem<T>(string s, Dictionary<string, T> dictionary, out T result) 
{ 
    if (dictionary.TryGetValue(s, out result)) { 
     return true; 
    } 
    return false; 

}

aktualisieren
Da Sie diesen Ansatz nicht gefällt, wie wäre es auf dem Kopf drehen?

public T TryParseDictionaryItem<T>(string s, Dictionary<string, T> dictionary, out bool Success) 
{ 
    T result = default(T); 
    Success = (dictionary.TryGetValue(s, out result)) 
    return result; 
} 
+0

Ja, ich sehe das, aber ich mochte diesen Ansatz nicht wirklich. Zum einen können Out-Parameter keine Klasseninstanzeigenschaften sein. Und ich finde es unangenehmer. –

Verwandte Themen