2012-04-28 10 views
5

Cercare alcune indicazioni sulle best practice. Diciamo che ho una linea di codice come questo:Come verificare null nei riferimenti annidati

Color color = someOrder.Customer.LastOrder.Product.Color; 

dove clienti, LastOrder, prodotto e colore potrebbe essere null in condizioni normali. Mi piacerebbe che il colore fosse nullo se uno qualsiasi degli oggetti nel percorso fosse nullo, comunque; per evitare eccezioni di riferimento null, dovrei verificare la condizione nulla per ognuno degli oggetti, ad es.

Color color = someOrder == null || 
       someOrder.Customer == null || 
       someOrder.Customer.LastOrder == null || 
       someOrder.Customer.Product == null ? 
       null : someOrder.Customer.LastOrder.Product.Color; 

o potrei fare questo

Color color = null; 
try {color = someOrder.Customer.LastOrder.Product.Color} 
catch (NullReferenceException) {} 

Il primo metodo funziona in modo chiaro, ma sembra un po 'più noioso per codice e difficile da leggere. Il secondo modo è un po 'più semplice, ma probabilmente non è una buona idea usare la gestione delle eccezioni per questo.

Esiste un altro modo di scorciatoia per verificare i valori nulli e assegnare un valore null al colore se necessario? O qualche idea su come evitare NullReferenceExceptions quando si utilizzano riferimenti annidati?

+2

possibile duplicato (http [profonda Null controllo, c'è un modo migliore?]: // StackOverflow .com/questions/2080647/deep-null-checking-is-there-a-better-way) –

+0

@MarkByers si, grazie per il rif to the oth domanda. Aggiornamento –

risposta

5

Si sta cercando l'operatore di dereferenziazione null-safe.

Color color = someOrder?.Customer?.LastOrder?.Product?.Color; 

Sfortunatamente C# non lo supporta. Forse verrà aggiunto più tardi, ma al momento non ci sono piani per farlo.

correlati

+4

2014, C# 6 lo supporta ora. –

+0

Ora supportato http://stackoverflow.com/a/2081709/1659248 –

0

avrei sicuramente preferisco il primo metodo ... la seconda sfrutta il meccanismo di eccezione per il flusso del programma che è una cattiva pratica IMHO ...

AFAIK non ci sono scorciatoie o "operatore di dereferenziazione zero-safe" in C#.

0

Definire un metodo univoco per l'accesso alle proprietà nidificate. Ad esempio come questo

private Customoer GetCustomer(Order order) 
{ 
    return order != null ? order.Customer : null; 
} 

private Order GetLastOrder(Customer customer) 
{ 
    return customer != null ? customer.LastOrder : null; 
} 

Utilizzando l'accesso metodo definito le proprietà attraverso l'applicazione

1

Le migliori pratiche è quello di seguire Law of Demeter che suona come: non parlare con gli sconosciuti. Cioè l'oggetto dovrebbe evitare di invocare i metodi di un oggetto membro restituito da un altro metodo. Ciò consente di scrivere codice meno accoppiato, più manutenibile e leggibile.

Quindi, evitare l'uso di "treni relitti" come someOrder.Customer.LastOrder.Product.Color, perché violano completamente la legge di Demeter. È persino difficile capire quale significato commerciale ha questo codice. Perché stai prendendo colore del prodotto di qualche altro ordine, che non è quello attuale?

Possibile modo di rimuovere il disastro ferroviario - spingere la funzionalità più vicino all'interessante fine del relitto. Nel tuo caso, considera anche di passare l'ultimo prodotto al tuo metodo, invece di usare qualche ordine.

+0

Grazie. Daro un'occhiata a LoD. A proposito, il codice era solo un esempio che ho inventato - nessun significato commerciale. –

+1

Mi piace che qualcuno abbia detto questo anche se non risponde direttamente alla domanda. Non c'è dubbio che devi scrivere codice complesso per assicurarti di non provare a utilizzare un riferimento null in codice come quello. Mentre è importante conoscere la risposta tecnica, compreso ciò che C# è in grado di fare e non è, questo tipo di codice dovrebbe spaventarti a guardare il tuo progetto generale. –

1

dove è necessario eseguire questa operazione.

Uso

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color); 

o

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color); 

classe helper Attuazione

public static class Complex 
{ 
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func) 
    { 
     return Get(() => func(root)); 
    } 

    public static T Get<T>(Func<T> func) 
    { 
     try 
     { 
      return func(); 
     } 
     catch (Exception) 
     { 
      return default(T); 
     } 
    } 
} 
Problemi correlati