2015-05-14 26 views
5

Sto provando a scrivere il seguente metodo utilizzando i generici. (Il mio metodo reale è più complessa di così.)Valore iniziale nullo per tipo sconosciuto

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 
} 

Il mio obiettivo è quello di tornare qualcosa come null se l'articolo non è presente nel dizionario.

Il problema è che non so quale sia il tipo T. Se T era un numero intero, ad esempio, dovrei restituire il tipo T?. Tuttavia, se T è una classe, allora è già annullabile. E non lo saprò fino all'ora legale.

Qualcuno può vedere un modo pulito per restituire un valore speciale in questo metodo per indicare che l'articolo non è valido? Sono aperto a restituire qualcosa di diverso da null, ma deve essere un valore speciale. (0 non è un valore speciale per i numeri interi.)

+0

Il meglio che puoi fare è "default (T)", ma non sarà "univoco" per un 'int'. –

+1

Il modo più semplice è creare due overload: uno per i tipi di classe e uno per le strutture nullable. In alternativa crea il tuo tipo 'Maybe ' e restituiscilo. – Lee

+1

Perché il chiamante non usa direttamente TryGetValue? Restituisce un bool che indica se l'elemento è valido e un parametro out ha l'oggetto, se valido. O se il metodo è più complicato, almeno qualcosa che segue quel modello. –

risposta

10

vorrei suggerire di restituire un ParseResult<T>, che è definito come qualcosa di simile a:

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

    // Accessors etc 
} 

In questo modo non c'è bisogno di preoccuparsi di valori Null, e si può farlo molto chiaro quello che stai facendo. Questo è lo schema che ho usato in Noda Time ea mio parere ha funzionato molto bene. (Attualmente usiamo una classe piuttosto che una struttura, ma potrei cambiare la situazione ...)

lo preferisco ad altri approcci, perché:

  • È pulito chiamare, a differenza utilizzando un parametro di out
  • non ha bisogno di brutto e potenzialmente costoso try/catch gestione
  • Si comporta esattamente allo stesso modo se T è un tipo di riferimento o di un tipo di valore
  • è flessibile it ough per rappresentare la situazione in cui nullè un valore parsing di successo
  • È ancora possibile propagare la causa di un fallimento senza gettare l'eccezione quando non è necessario
+0

Grazie, stavo pensando di restituire una lezione con informazioni aggiuntive ma speravo in qualcosa di più leggero e semplice. Ma forse è questo l'approccio migliore. –

+0

Mi trovo a usare questo modello sempre di più. – Matthew

+1

Se solo 'Nullable' non ha il vincolo che l'argomento generico sia un tipo di valore ... – Servy

4

È possibile creare due metodi uno per tipi di valore e un altro per tipo di riferimento. Il metodo del tipo di valore restituirà T? anziché T. In entrambi i metodi, è possibile restituire null per indicare un valore non valido.

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

Forse due overload aiuterebbe:

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 Lo so, hanno nomi diversi. –

+0

Mi dispiace, l'avevo appena notato. Procedere. –

0

Perché reinventare la ruota? Date un'occhiata al vostro codice:
Si sta utilizzando il metodo TryGetValue del dizionario. Come gestisce lo stesso problema?
Ti suggerisco di seguire le orme del.Gli sviluppatori NET Framework e fanno lo stesso:

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

}

Aggiornamento
Dal momento che non vi piace questo approccio, come su trasformandolo su di essa la testa?

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

Sì, lo vedo, ma non mi è piaciuto molto questo approccio. Per prima cosa, i parametri 'out' non possono essere proprietà di istanze di classe. E lo trovo più imbarazzante. –