2010-10-09 18 views
6

possibili duplicati:
Deep Null checking, is there a better way?
C# elegant way to check if a property's property is nullCome evitare multipla se controlli nulli

devo fare una ricerca in un modello a oggetti profonda come questo:

p.OrganisationalUnit.Parent.Head.CurrentAllocation.Person; 

c'è comunque da valutare e restituire null se c'è o f la catena è nullo (OrganizationalUnit, genitore, di testa, ecc), senza dover fare un

if (p.org == null && p.org.Parent == null && p.org.Parent.Head . . .  
+0

Cercare di evitare questo tipo di ricerca; si prega di vedere la mia risposta qui sotto per i dettagli. – CesarGon

risposta

8

Stai cercando il nulla-safe operatore dereference ?. (noto anche come una navigazione sicura) che alcune lingue (per esempio Groovy), ma sfortunatamente C# non ha questo operatore.

Speriamo che sarà attuato uno giorno ....

Vedi anche this post da Eric Lippert. La sintassi che propone è .?.

+0

È più spesso chiamato ** operatore di propagazione nullo ** o ** operatore condizionale nullo **. –

+1

Ora è disponibile su C# 6: https://msdn.microsoft.com/en-us/library/dn986595.aspx –

7

Avete sentito parlare del Law of Demeter?

Concatenare sequenze di chiamate così lunghe non è una buona idea. Crea dipendenze terribili tra le classi che non ti servono.

Nell'esempio, la classe contenente p diventa dipendente da cinque classi cinque. Ti suggerisco di semplificare il tuo codice e fare in modo che ogni classe controlli i null a un unico livello, nel loro contesto di conoscenza.

+0

d'accordo ma preso su una grande base di codice, non può refactoring tutto in un giorno :) – leora

+0

@ooo: capisco. In tal caso, penso che sia necessario utilizzare la brutta catena di assegni nulli. Cercherò di incapsulare questo in un metodo privato in modo che le dipendenze siano isolate e facilmente riconoscibili. – CesarGon

0

Per rispondere alla domanda nel titolo, è possibile evitare applicando la 'legge di Demetra' e la creazione di un metodo chiamato GetHeadOfParentOrganizationalUnit()

Non sono sicuro se la soluzione si applica per il vostro caso specifico, ma vale la pena dare un'occhiata se è possibile eliminare tutti quei controlli nulli.

Consulta anche: a link

+1

ma poi la funzione GetHeadofParent. .avresti solo lo stesso controllo nidificato nullo – leora

+1

@oooo - Non sei davvero in grado di un livello alla volta. Ogni classe parla solo con il suo immediato collaboratore, non si introduce l'interno del collaboratore per strappare uno stato annidato ... * leggi sulla legge di demeter *. Da wikipedia - Uno svantaggio della legge di Demeter è che a volte richiede la scrittura di un gran numero di piccoli metodi "wrapper" per propagare le chiamate di metodo ai componenti. Inoltre, l'interfaccia di una classe può diventare ingombrante poiché ospita metodi per classi contenute, risultando in una classe senza un'interfaccia coesa. Ma questo potrebbe anche essere un segno di cattivo design OO. – Gishu

6

Partenza this article. Presenta una grande soluzione che permette di scrivere cose del genere:

p.With(x => x.OrganisationalUnit) 
.With(x => x.Parent) 
.With(x => x.Head) 
.With(x => x.CurrentAllocation 
.With(x => x.Person); 
-2

È possibile utilizzare la gestione di base eccezioni come pure per la cattura di questo. Non sono pazzo di quella soluzione, ma è un'opzione. Se questi valori nidificati sono normali, le eccezioni probabilmente non sono la risposta corretta:

public class A 
{ 
} 
public class B 
{ 
    public A a; 
} 
public class C 
{ 
    public B b; 
} 
class Program 
{ 
    static A GetA(C c) 
    { 
     A myA; 
     try 
     { 
      myA = c.b.a; 
     } 
     catch 
     { 
      myA = null; 
     } 
     return myA; 
    }   

    static void Main(string[] args) 
    { 
     C theC = new C(); 
     theC.b = new B(); 
     theC.b.a = new A(); 
     A goodA = GetA(theC); 
     if (goodA != null) 
     { 
      Console.WriteLine("Expected nominal path."); 
     } 
     else 
     { 
      Console.WriteLine("Unexpected nominal path."); 
     } 
     theC.b.a = null; 
     A badA = GetA(theC); 
     if (badA == null) 
     { 
      Console.WriteLine("Expected off-nominal path."); 
     } 
     else 
     { 
      Console.WriteLine("Unexpected off-nominal path."); 
     } 

    } 

} 
+0

Il richiamo del sistema di gestione delle eccezioni sembra eccessivo per le normali operazioni; comunque come hai detto è una soluzione, pensando fuori dagli schemi. –

+0

@John K: Sono d'accordo: l'unico modo in cui potrei mai considerarlo è che qualsiasi null annidato rappresentasse uno stato "rotto". Inoltre, c'è il problema di non sapere quale dereferenziamento ha infranto il sistema e il colpo di prestazioni. Ma è uno strumento nella scatola ... – PatrickV

Problemi correlati