Entwickler-Ecke

IO, XML und Registry - SelectSingleNode bei Nichtvorhandensein effizient lösen


erfahrener Neuling - Mi 09.03.16 15:01
Titel: SelectSingleNode bei Nichtvorhandensein effizient lösen
Hallo,

Ich habe vor kurzem angefangen, mich mit xml zu beschäftigen und kenne mich nocht nicht gut aus.
Momentan schreibe ich ein Programm, welches SQL-Code in etwas anderes umwandeln soll.
Dabei habe ich folgendes Problem, dass ich einen Knotenpunkt ansteuern will, der aber nicht in jeder Zeile vorkommen muss.
D.h. wenn dieser Knotenpunkt nicht vorhanden ist, gibts eine Exception.
Mein Code dazu sieht so aus

C#-Quelltext
1:
2:
3:
4:
5:
6:
try 
{
    MemberName = columnNode.SelectSingleNode("./@Member").Value;    //falls Member existiert, kein Problem
    Line += " ColumnName='" + MemberName + "'"; }
}    
catch (NullReferenceException) {}

Problem: seit ich das mit try-catch hinzugefügt habe, braucht der Process viel länger als ohne try-catch

Frage: Kann man das irgendwie lösen, in dem man vorher abfragt, ob 'Member' überhaupt vorhanden ist, a la

C#-Quelltext
1:
if(columnNode.proofExistence("./@Member") {...}                    

ohne dass eine Exception das ganze unnötig verlängert?

Gruß
Neuling


Th69 - Mi 09.03.16 15:09

Eine NullReferenceException ist immer ein Programmierfehler und sollte niemals per catch abgefangen werden.
In deinem Fall mußt du nur vorher prüfen, ob null zurückgeliefert wird, bevor du auf Value zugreifst, also

C#-Quelltext
1:
2:
3:
4:
5:
var node = columnNode.SelectSingleNode("./@Member");
if (node != null)
{
    MemberName = node.Value;
}

In C#6 kannst du auch mittels des ?.-Operators arbeiten:

C#-Quelltext
1:
MemberName = columnNode.SelectSingleNode("./@Member")?.Value;                    

MemberName hat dann, wenn der Knoten nicht gefunden wird, den Default-Datenwert von Value (d.h. bei einem string also null).


Christian S. - Mi 09.03.16 15:25

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
MemberName hat dann, wenn der Knoten nicht gefunden wird, den Default-Datenwert von Value (d.h. bei einem string also null).
Meines Wissens ist der Rückgabewert bei Verwendung von "?" ein Nullable des Grundtyps, das heißt wenn der Knoten nicht gefunden wird, ist der Rückgabewert null (was bei string natürlich keinen Unterschied macht, bei int aber z.B. schon ;-))


erfahrener Neuling - Mi 09.03.16 15:45

Super! Genau das hab ich gebraucht.. hatte gar nicht mehr auf das .Value geachtet, aber so machts natürlich Sinn


erfahrener Neuling - Mi 09.03.16 16:02

Hab doch noch ne Frage

die Datei hat folgenden Aufbau:

XML-Daten
1:
2:
3:
4:
5:
6:
7:
<?xml version="1.0" encoding="utf-8"?>
<Database Name="..." Class="...">
  <Connection ... />
  <Table Name="dbo.ADRESSEN" Member="Adressen">
      .
      .
      .

Frage: Wie komme ich an die Kopfzeile per xml-Befehl? per selectNode klappt es jedenfalls nicht
Frage 2: Wieso klappt es nicht, was ist besonders an dieser Zeile?


Th69 - Mi 09.03.16 16:52

@Christian: wir beide hatten nicht komplett recht ;-)

Bei Wertetypen wird ein Nullable<T> zurückgegeben, bei Referenztypen aber bleibt es so (denn Nullable<T> gibt es nur bei Wertetypen):

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
using System;

public class Test
{
  class A
  {
    internal int x;
    internal string y;
  }
  
  public static void Main()
  {
    A a = null;
    
    int? x = a?.x;
    string y = a?.y; // string? gibt Compiler-Fehler...
    
    Console.WriteLine(x);
    Console.WriteLine(y);
  }
}

Bei Wertetypen ist also der ?.-Operator genauso unelegant, wie das Prüfen auf null, da man dann anschließend beim Zugriff auf dessen Value mittels HasValue überprüfen muß, ob überhaupt ein Wert vorliegt.

@erfahrener Neuling:
Mittels

C#-Quelltext
1:
XmlDeclaration dec = doc.FirstChild as XmlDeclaration;                    

solltest du an den Header herankommen, aber warum benötigst du diese Info?


Christian S. - Mi 09.03.16 17:00

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
@Christian: wir beide hatten nicht komplett recht ;-)
:zustimm:


user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Bei Wertetypen ist also der ?.-Operator genauso unelegant, wie das Prüfen auf null, da man dann anschließend beim Zugriff auf dessen Value mittels HasValue überprüfen muß, ob überhaupt ein Wert vorliegt.

Oder man macht sowas:

C#-Quelltext
1:
int x = a?.x ?? 42;                    


Th69 - Mi 09.03.16 17:06

@Christian: Wow, super Lösung (nur daß man dann selber immer den Default-Wert hinschreiben muß)!

Ich plädiere für den ??.-Operator:

C#-Quelltext
1:
int x = a??.x : 42;                    

oder gleich mit integriertem Default-Wert:

C#-Quelltext
1:
int x = a??.x;                    

:D