2009-04-27 7 views
12
<?xml version="1.0" encoding="utf-8" ?> 
<pages> 
    <page id="56"> 
    <img id="teaser" src="img/teaser_company.png"></img> 
    </page> 
</pages> 

Ho un file xml che definisce risorse aggiuntive per le pagine all'interno di un cms. Qual è il modo migliore per proteggere le eccezioni di riferimento Null quando si esegue una query su questo file con LinqToXml?Come si fa a proteggere le eccezioni di riferimento Null in Linq To Xml?

var page = (from tabElement in extensionsDoc.Descendants("page") 
where tabElement.Attribute("id").Value == tabId.ToString() 
select tabElement).SingleOrDefault(); 

Questo codice potrebbe potenzialmente innescare un'eccezione di riferimento NULL se un elemento della pagina non ha un attributo chiamato "id". Devo usare un catch catch try o esiste un modo per gestirlo? Ad esempio, restituisce null per pagina l'oggetto pagina se non c'è alcun attributo chiamato "id" per l'elemento page.

+0

Come circa il controllo in anticipo il tabid? –

risposta

28

EDIT: Questo è stato scritto chiaramente molto tempo fa - in questi giorni mi piacerebbe sicuramente andare con il cast come per la risposta di Igor.

Il modo più semplice sarebbe qualcosa di simile:

var page = (from tabElement in extensionsDoc.Descendants("page") 
      let idAttribute = tabElement.Attribute("id") 
      where idAttribute != null 
        && idAttribute.Value == tabId.ToString() 
      select tabElement).SingleOrDefault(); 

In alternativa si potrebbe scrivere un metodo di estensione per XElement:

public static string AttributeValueOrDefault(this XElement element, 
              string attributeName) 
{ 
    XAttribute attr = element.Attribute(attributeName); 
    return attr == null ? null : attr.Value; 
} 

quindi utilizzare:

var page = (from element in extensionsDoc.Descendants("page") 
      where element.AttributeValueOrDefault("id") == tabId.ToString() 
      select element).SingleOrDefault(); 

O, per usare dot notazione:

var page = extensionsDoc.Descendants("page") 
      .Where(x => x.AttributeValueOrDefault("id") == tabId.ToString()) 
      .SingleOrDefault(); 

(Avrebbe senso per chiamare tabId.ToString() una volta in anticipo, btw, piuttosto che per ogni iterazione.)

+0

Il metodo di estensione funziona solo se non è necessaria una proprietà dell'attributo, come la sua lunghezza. 'x.AttributeValueOrDefault (" id "). Length> 0', ad esempio, genererà comunque una NullReferenceException. Penso che usare 'let' sia più sicuro. _BTW, sfortunatamente, ReSharper non avverte su una possibile NullReferenceEception se si usa _ 'let' _e non si controlla per_' null'. – comecme

+0

@comecme: in questo caso è possibile utilizzare l'operatore con coalizione nulla. Non è stato pensato per essere una panacea ... anche se l'utilizzo del cast esplicito sarebbe davvero meglio qui. –

3

Ho visto altre persone usano un cast dritto in una stringa prima pure; Non so se è più o meno efficiente di quello che Jon ha suggerito, ma mi piace molto la sintassi.

var page = extensionsDoc.Descendants("page") 
      .Where(x => (string)x.Attribute("id") == tabId.ToString()) 
      .SingleOrDefault(); 

Chiunque si sentono liberi di stabilire che se c'è qualche difetto nel mio pensiero; Sono abbastanza nuovo di LINQ.

1

Tendo ad utilizzare le espressioni XPath in cui il codice sarebbe altrimenti ingombrato da molti controlli Null. Per il tuo esempio:

var query = string.Format("page[@id='{0}']", tabId.ToString()); 
var page = extensionsDoc.XPathSelectElement(query); 
10

In .NET 4 LINQ to XML fornisce un modo per farlo ed è attraverso l'utilizzo explicit casts:

var page = (
    from tabElement in extensionsDoc.Descendants("page") 
    where (string)tabElement.Attribute("id") == tabId.ToString() 
    select tabElement 
).SingleOrDefault(); 

Se l'attributo non c'è, allora il risultato sarà semplicemente essere nullo

Oltre all'operatore esplicito string ci sono anche la maggior parte dei tipi primitivi e le loro versioni Nullable. Questo significa che si può fare AttributeOrDefault usando questo tipo di sintassi:

//<element theAttr="12" /> 
int theAttr = (int?)doc.Element("element").Attribute("missingAttr") ?? 0; 
+2

L'ultimo esempio potrebbe generare una NullReferenceException se non esiste alcun elemento "elemento" '. – comecme

0

userei un'entità di classe mappatura l'elemento XML. E chiama un metodo che controlli il valore nullo. Io uso questo metodo nel mio codice, funziona bene. Spero che sia d'aiuto.

Ecco un codice di esempio per regolare a seconda delle esigenze:

private void Method1(...) { 
    ... 

    var pages = from tabElement in extensionsDoc.Descendants("page") 
    where tabElement.Attribute("id").Value == tabId.ToString() 
    select new Page { 
       imgSrc = Method2(tabElement) 
      }; 

    // pages variable is a List<Page> object 
    ... 
} 

private void Method2(XElement element) { 
    XElement img = element.Element("img"); 

    if (img != null) { 
     ... 
     // TODO return the imgSrc 
     return ""; 
    } 

    // return null or "" 
    return null; 
} 

Poi la definizione della classe Pagina:

class Page 
{ 
    public string imgSrc { get; set; } 
} 
+0

Se 'tabElement' non ha un attributo' "id" ', ciò causerebbe comunque una NullReferenceException nel' Metodo1'. – comecme

Problemi correlati