2012-10-02 9 views
7

Ich versuche zu verhindern, NULL-Werte zu haben, wenn ich eine XML-Datei mit LINQ zu einem benutzerdefinierten Objekt analysiere.C# ?? null Koaleszenzoperator LINQ

Ich fand eine großartige Lösung für dieses auf Scott Gu's blog, aber aus irgendeinem Grund funktioniert es nicht für Ganzzahlen mit mir. Ich denke, ich habe die gleiche Syntax verwendet, aber es scheint, dass mir etwas fehlt. Oh, und aus irgendeinem Grund funktioniert es, wenn der Knoten nicht leer ist.

Unten ist ein Auszug aus meinem Code.

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
     select new GrantAgresso() 
     { 
      Year = (int?)g.Element("yearnode") ?? 0, 
      Subdomain = (string)g.Element("domainnode") ?? "" 
     }).ToList(); 

Die Fehlernachricht ist:

Input string was not in a correct format.

Wenn jemand eine Ahnung, hat, was ich falsch mache, bitte helfen :)

Edit: Stück XML (seltsame Namen, aber es ist nicht durch Wahl)

<Agresso> 
    <AgressoQE> 
    <r3dim_value>2012</r3dim_value> 
    <r0r0r0dim_value>L5</r0r0r0dim_value> 
    <r7_x0023_province_x0023_69_x0023_V005>0</r7_x0023_province_x0023_69_x0023_V005> 
    <r7_x0023_postal_code_x0023_68_x0023_V004 /> 
    <r7_x0023_country_x0023_67_x0023_V003>1004</r7_x0023_country_x0023_67_x0023_V003> 
    <r7_x0023_communitydistrict_x0023_70_x0023_V006>0</r7_x0023_communitydistrict_x0023_70_x0023_V006> 
    </AgressoQE> 
</Agresso> 
+1

Meine Wette ist auf eine falsche XML-Syntax. Können Sie den XML-Inhalt anzeigen? Der Coalesce-Operator hat Recht und wenn nicht, würde es diesen Fehler nicht auslösen (es hat nichts mit Strings zu tun) –

+0

Ist die 'Year'- oder' Subdomain'-Zuweisung die Ausnahme? Sie könnten versuchen, eine der Zeilen zu kommentieren, um zu sehen, ob die Ausnahme verschwindet. – Mizipzor

+0

Ich habe einen Knoten des xml zu meinem Beitrag hinzugefügt. Es ist der leere Knoten (beginnend mit r7_), der die Ausnahme auslöst. Der Code, mit dem ich ihn abgerufen habe, ist derselbe, den ich für das Jahr verwendet habe. – Nielsm

Antwort

1

Die folgende Erweiterung Methode 0 zurück, wenn sowohl das Element nicht vorhanden ist, ist das Element leer oder es enthält eine Zeichenfolge, die ganze Zahl sein kann nicht analysiert zu:

public static int ToInt(this XElement x, string name) 
    { 
     int value; 
     XElement e = x.Element(name); 
     if (e == null) 
      return 0; 
     else if (int.TryParse(e.Value, out value)) 
      return value; 
     else return 0; 
    } 

Sie es wie folgt verwenden:

... 
Year = g.ToInt("r3dim_value"), 
... 

Oder wenn Sie bereit sind, die Kosten für die Reflexion zu berücksichtigen und den Standardwert eines Werttyp zu akzeptieren, können Sie diese Erweiterung Methode verwenden:

public static T Cast<T>(this XElement x, string name) where T : struct 
{ 
    XElement e = x.Element(name); 
    if (e == null) 
     return default(T); 
    else 
    { 
     Type t = typeof(T); 
     MethodInfo mi = t.GetMethod("TryParse", 
            BindingFlags.Public | BindingFlags.Static, 
            Type.DefaultBinder, 
            new Type[] { typeof(string), 
               t.MakeByRefType() }, 
            null); 
     var paramList = new object[] { e.Value, null }; 
     mi.Invoke(null, paramList); 
     return (T)paramList[1]; //returns default(T), if couldn't parse 
    } 
} 

und verwenden es:

... 
Year = g.Cast<int>("r3dim_value"), 
... 
+0

Ich habe Ihren zweiten Vorschlag verwendet. Danke! – Nielsm

1

können Sie Where operator

hinzufügen
..... 
.Where(a => ! string.IsNullOrEmpty(a)).ToList(); 
+0

Was soll 'a' hier sein? Warum rufen Sie 'ToList' auf, was aussieht wie ein' IEnumerable '? – Rawling

+2

Dies ist nicht das, was das OP versucht zu tun. –

+1

Nein, ich kann nicht, ich möchte die Ergebnisse nicht filtern, ich möchte nicht, dass mein Programm bricht, wenn ein leerer Knoten erscheint ... – Nielsm

1

Wenn Jahr null ist oder leer Zeichenfolge, die Sie eine „Eingabezeichenfolge in einer korrekten Format nicht“ Ausnahme erhalten. Sie können eine Erweiterungsmethode zum Lesen von Werten schreiben. Ich habe den Code unten nicht getestet, kann Ihnen aber Hinweise geben.

public static ReadAs<T>(this XElement el, T defaultValue) { 
    var v = (string)el; // cast string to see if it is empty 

    if (string.IsNullOrEmpty(v)) // test 
    return defaultValue; 

    return (T)el; // recast to our type. 
} 
2

Es ist dieser Ausdruck, der zu werfen ist:

(int?)g.Element("yearnode") 

das, weil ist, wenn der tatsächliche Wert des Textknotens Element String.Empty und nicht null ist, da die leere Zeichenkette für Int32.Parse kein gültiges Format , der versuchte Cast schlägt fehl.

Wenn das Element vollständig in Ihrem XML fehlt, funktioniert dies wie erwartet, aber wenn ein leeres Tag <yearnode/> oder <yearnode></yearnode> ist, erhalten Sie die Ausnahme.

+0

Dies könnte die Antwort sein, nach der ich gesucht habe. Was würdest du mir vorschlagen? – Nielsm

1

Die Nachricht Input string was not in a correct format sieht aus wie der von int.parse() geworfen man so könnte es sein, dass Sie ein yearnode mit einem Wert (nicht null), aber die auf einen ganzzahligen Wert analysiert können nicht erfolgreich sein.

Etwas wie dies das Problem beheben kann:

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
    let yearNode = g.Element("yearnode") 
    select new GrantAgresso 
    { 
     Year = string.IsNullOrWhiteSpace(yearNode.Value) ? 0 : int.Parse(yearNode.Value), 
     Subdomain = g.Element("domainnode").Value 
    }).ToList(); 

Ein paar Dinge zu beachten:

select new GrantAgresso - Sie brauchen keine Klammern für einen Standard-Konstruktor mit Objektinitialisierer.

string.IsNullOrWhiteSpace - wurde in .net 4.0 eingeführt, verwenden Sie string.IsNullOrEmpty, wenn Sie auf 3 sind.5 oder früher

g.Element("domainnode").Value - immer einen String zurück

, wenn Sie eine Null im Jahr statt 0, (int?)null statt 0

+0

Hallo, Ich habe nur Double & Triple überprüft meine XML, die Werte, die ich in int konvertieren möchten, sind entweder leer oder eine gültige ganze Zahl. Das habe ich auch in Betracht gezogen ;-) – Nielsm

+0

Ich habe meine Antwort mit einem Vorschlag zum Umgang mit dem Leergut aktualisiert. –

0

Ihr Problem ist verwendet werden sollen, dass die Besetzung von XElement in int? verwendet die int.Parse-Methode für den Zeichenfolgenwert des XElement, in Ihrem Fall String.Empty. Die folgenden Ergebnisse in dem gleichen Fehler:

XElement x = new XElement("yearnode", String.Empty); 
int? a = (int?)x; // throws FormatException 

Sie diese zuerst vermeiden, indem XElement bespannen Gießen und prüfen, ob es null oder leer ist und nur dann, wenn nicht die Besetzung tun int ?. Dazu ersetzen

Year = (int?)g.Element("yearnode") ?? 0, 

mit

Year = !string.IsNullOrEmpty((string)g.Element("yearnode")) ? (int?)g.Element("yearnode") : 0, 

Es ist nicht schön und wird immer noch aus, wenn die Zeichenfolge sonst nicht legal, aber es funktioniert, wenn Sie davon ausgehen können, dass das Element ist immer eine ganze Zahl oder null/leer.