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

Ich habe eine XML-Datei, die zusätzliche Ressourcen für Seiten innerhalb eines cms definiert. Was ist der beste Weg, um Ausnahmen von Null-Referenz zu schützen, wenn Sie diese Datei mit LinqToXml abfragen?Wie schützen Sie Ausnahmen von Null Reference in Linq To Xml?

Dieser Code kann möglicherweise eine Null Reference-Ausnahme auslösen, wenn ein Seitenelement kein Attribut namens "id" aufweist. Muss ich einen try catch-Block verwenden oder gibt es einen Weg, damit umzugehen? Geben Sie beispielsweise null für die Seite des Seitenobjekts zurück, wenn kein Attribut namens "id" für das Seitenelement vorhanden ist.

+0

Wie wäre die Überprüfung im Vorfeld der tabId? –

Antwort

28

EDIT: Das war klar vor langer Zeit geschrieben - in diesen Tagen würde ich definitiv mit der Besetzung nach Igors Antwort gehen.

Der einfachste Weg wäre so etwas wie:

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

Alternativ können Sie eine Erweiterungsmethode zu XElement schreiben:

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

dann verwenden:

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

oder Punkt zu verwenden, Notation:

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

(Es wäre sinnvoll, tabId.ToString() zu nennen einmal vorher, btw, anstatt für jede Iteration.)

+0

Die Erweiterungsmethode funktioniert nur, wenn Sie eine Eigenschaft des Attributs nicht benötigen, z. B. seine Länge. 'x.AttributeValueOrDefault (" id "). Length> 0' zum Beispiel wird immer noch eine NullReferenceException auslösen. Ich denke, mit "Let" ist sicherer. _BTW, leider warnt ReSharper nicht vor einer möglichen NullReferenceEception, wenn Sie _ let' _ verwenden und nicht nach_ 'null' suchen. – comecme

+0

@comecme: In diesem Fall könnten Sie den Nullkoaleszenzoperator verwenden. Es sollte kein Allheilmittel sein ... obwohl die explizite Besetzung hier eigentlich besser wäre. –

3

ich andere Leute vor als auch eine gerade gegossen in einen String verwenden gesehen habe; Ich weiß nicht, ob es mehr oder weniger effizient ist als das, was Jon vorgeschlagen hat, aber ich mag die Syntax sehr.

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

Jeder kann das reparieren, wenn es einen Fehler in meinem Denken gibt; Ich bin ziemlich neu in LINQ.

1

Ich neige dazu, XPath-Ausdrücke zu verwenden, bei denen der Code ansonsten mit vielen Null-Prüfungen überladen wäre. Für Ihr Beispiel:

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

In .NET 4 LINQ to XML bietet eine Möglichkeit, das zu tun, und es ist durch explicit casts mit:

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

Wenn das Attribut nicht vorhanden ist, dann wird das Ergebnis einfach sei null.

Zusätzlich zum expliziten Operator string gibt es auch die meisten primitiven Typen und ihre Nullable-Versionen. Dies bedeutet, dass Sie AttributeOrDefault mit dieser Art von Syntax tun können:

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

Ihr letztes Beispiel könnte eine NullReferenceException enthalten, wenn kein Element '" element "existiert. – comecme

0

würde ich eine Klasse Entität das XML-Element Mapping verwenden. Und rufe eine Methode auf, die den Nullwert überprüft. Ich verwende diese Methode in meinem Code, es funktioniert gut. Ich hoffe es hilft.

Hier ist ein Beispielcode je nach Ihren Bedürfnissen anzupassen:

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; 
} 

Dann wird die Seite Klassendefinition:

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

Wenn 'tabElement' kein Attribut' "id" hat, würde das immer noch eine NullReferenceException in Ihrer 'Methode1' verursachen. – comecme