Fragensteller
C# Problem beim Laden einer Liste (NullReferenceException)

Frage
-
Ich versuche einen ContactManager zu programmieren, jedoch habe ich ein Problem. Beim Laden der Liste wo die Kontakte gespeichert sind scheitert das Programm an der Methode "public override string ToString()". Die Methode nimmt die Werte des getters nicht an und liefert mir immer eine NullReferenceException.
public override string ToString()
{
return Vorname.ToString() + " ; " + Nachname.ToString()
+ " ; " + Alter.ToString()
+ " ; " + Land.ToString()
+ " ; " + Ort.ToString()
+ " ; " + PLZ.ToString()
+ " ; " + Strasse.ToString()
+ " ; " + Hausnummer.ToString()
+ " ; " + TelNummer.ToString();
}Es könnte jedoch vielleicht an der Methode "DisplayItems" liegen.
private void DisplayItems()
{
foreach (CPerson c in cm.Liste)
{
if (c != null)
{
lbxList.Items.Add(c.ToString());
}
}
}Ich freue mich über Ihre Antwort.
Alle Antworten
-
Sie werden über einen Konstruktor initialisiert.
private string sVorname;
public CPerson(string sVorname, string sNachname, string iAlter, string sLand, string sOrt, string iPostleihZahl, string sStraße, string sHausnummer, string Telefonnummer)
private string sNachname;
private string iAlter;
private string sStrasse;
private string sOrt;
private string sLand;
private string sHausnummer;
private string iPostleihZahl;
private string Telefonnummer;
{
this.sVorname = sVorname;
this.sNachname = sNachname;
this.iAlter = iAlter;
this.sStrasse = sStraße;
this.sHausnummer = sHausnummer;
this.iPostleihZahl = iPostleihZahl;
this.sOrt = sOrt;
this.sLand = sLand;
this.Telefonnummer = Telefonnummer;
}und dann noch mit den jeweiligen gettern und settern.
-
Zeig uns mal genug Code, der es uns erlaubt, das Problem zu reproduzieren, die Deklaration der in der Methode
public override string ToString()
{
return Vorname.ToString() + " ; " + Nachname.ToString()
+ " ; " + Alter.ToString()
+ " ; " + Land.ToString()
+ " ; " + Ort.ToString()
+ " ; " + PLZ.ToString()
+ " ; " + Strasse.ToString()
+ " ; " + Hausnummer.ToString()
+ " ; " + TelNummer.ToString();
}benutzen Eigenschaften wie Vorname usw. hast du uns immer noch nicht gezeigt, und wenn z.b. Vorname vom Typ string ist, aber null ist, dann gibt Vorname.ToString() halt eine NullReferenceException. Analog für die anderen Eigenschaften, also untersuche mal deinen Code, oder poste genug Details, die uns erlauben, das Problem zu reproduzieren.
MVP Data Platform Development My blog
-
Nun gut hier sind alle Codes die dazu gehören.
public class ContactManagerLogik
{public CPerson Find(CPerson person)
{
for (int i = 0; i < _Elements; i++)
{
if (_Liste[i] == null)
{
MessageBox.Show("Kontakt nicht gefunden");
break;
}
if (_Liste[i].Vorname == person.Vorname)
{
return _Liste[i];
}
}
return person;
}
public void Load()
{
StreamReader Reader = new StreamReader("Liste.csv");
while (!Reader.EndOfStream)
{
string s = Reader.ReadLine();
Add(new CPerson(s));
}
}
public CPerson[] Liste
{
get
{
return _Liste;
}
}
}public class CPerson
{
private string sVorname;
private string sNachname;
private string iAlter;
private string sStrasse;
private string sOrt;
private string sLand;
private string sHausnummer;
private string iPostleihZahl;
private string Telefonnummer;
private string p;
private string p_2;
private string p_3;
private string p_4;
private string p_5;
public CPerson(string importline)
{
string[] Line = importline.Split(';');
}
public CPerson(string sVorname, string sNachname, string iAlter, string sLand, string sOrt, string iPostleihZahl, string sStraße, string sHausnummer, string Telefonnummer)
{
this.sVorname = sVorname;
this.sNachname = sNachname;
this.iAlter = iAlter;
this.sStrasse = sStraße;
this.sHausnummer = sHausnummer;
this.iPostleihZahl = iPostleihZahl;
this.sOrt = sOrt;
this.sLand = sLand;
this.Telefonnummer = Telefonnummer;
}
public CPerson(string p, string p_2, string p_3, string p_4, string p_5)
{
this.p = p;
this.p_2 = p_2;
this.p_3 = p_3;
this.p_4 = p_4;
this.p_5 = p_5;
}
public string Vorname
{
get
{
return this.sVorname;
}
set
{
this.sVorname = value;
}
}
public string Nachname
{
get
{
return this.sNachname;
}
set
{
this.sNachname = value;
}
}
public string Alter
{
get
{
return this.iAlter;
}
set
{
this.iAlter = value;
}
}
public string Strasse
{
get
{
return this.sStrasse;
}
}
public string Hausnummer
{
get
{
return this.sHausnummer;
}
}
public string Ort
{
get
{
return this.sOrt;
}
}
public string PLZ
{
get
{
return this.iPostleihZahl;
}
}
public string Land
{
get
{
return this.sLand;
}
}
public string TelNummer
{
get
{
return this.Telefonnummer;
}
set
{
this.Telefonnummer = value;
}
}
public override string ToString()
{
return Vorname.ToString() + " ; " + Nachname.ToString()
+ " ; " + Alter.ToString()
+ " ; " + Land.ToString()
+ " ; " + Ort.ToString()
+ " ; " + PLZ.ToString()
+ " ; " + Strasse.ToString()
+ " ; " + Hausnummer.ToString()
+ " ; " + TelNummer.ToString();
}
}public partial class FrmMain : Form
{
ContactManagerLogik cm = new ContactManagerLogik();
public FrmMain()
{
InitializeComponent();
}
private void DisplayItems()
{
foreach (CPerson c in cm.Liste)
{
if (c != null)
{
lbxList.Items.Add(c.ToString());
}
}
}Sollten das Problem nach wie vor unklar sein könnte ich Ihnen das Programm per e-mail zukommen lassen.
-
Sollte im Konstruktor
public CPerson(string importline)
{
string[] Line = importline.Split(';');
}
nicht mehr passieren, als nur die Zeile aufzubrechen? Sollten nicht insbesondere die Felder initialisiert werden, vermutlich mit Werten aus dem string-Array "Line"?
MVP Data Platform Development My blog
-
Hi,
ich verstehe in Deinem ersten Posting nicht, wieso Du nicht sagen kannst, in welcher Methode der Fehler auftritt. Weißt Du, wie man den VS-Debugger benutzt?
Eigentlich müsste es schon reichen, das Programm in der Debug-Konfiguration laufen zu lassen (F5) und zu warten, dass VS bei der Exception stehen bleibt. Dann kannst Du Dir "this" angucken und weißt, welche Eigenschaft zu der Exception geführt hat (s. Martins zweiten Post). Dann ist es schon mal deutlich einfacher, nach einer Ursache dafür zu suchen.
Wenn das nicht reicht, solltest Du sicherstellen,
- dass der constructor mit den vielen Parametern bei der Erzeugung der Objekle verwendet wird und
- dass an diesen constructor keine NULL-Werte übergeben werden.
Du könntest auch die ToString-Methode einfacher prüfbar machen, indem Du nicht alles in einer Zeile zuweist, sondern das Ergebnis in einzelnen Anweisungen Eigenschaft um Eigenschaft zusammensetzt.
Gruß
Jürgen -
Ich habe doch dazu geschrieben, dass das Problem beim override liegt ich werde mir das jetzt alles nochmal genau anschauen.
Das hindert dich aber nicht daran, einen Breakpoint auf die entsprechende Zeile zu setzen und dann dort zu schauen, welche der Eigenschaften, die Du ansprichst, null ist. Einfach Breakpoint setzen, F5 drücken (debuggen) und prüfen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
habe ich natürlich auch auch schon gemacht. Ich denke, das Problem ist, dass das Programm etwas relevantes überspringt.
Ich denke eher, dass das Problem bei dir liegt. Wenn etwas relevantes übersprungen werden sollte, liegt das ja an deinem Code. Daher solltest Du uns mal die notwendigen Infos geben und dazu musst Du zuerst einmal Schritt für Schritt durch dein Programm laufen. Das wiederum geht per Debugger und dann F10, F11, ...
Ich persönlich würde auch drauf tippen, dass dein (ohne weiteren Code sinnfreier) Konstruktor "public CPerson(string importline)" "Schuld" ist.
"Schuld" deshalb, da Du davon ausgehst, dass immer alle Werte gefüllt sind und kein Wert null sein kann. Darauf würde ich aber nicht wetten.
Daher nochmal: Setz bitte erstmal einen Breakpoint auf die Zeile "return Vorname.ToString() + " ; " + Nachname.ToString()..." und schau dann, welche der Eigenschaften null ist. Ich würde mal sagen: Alle :)
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
"public CPerson(string importline)" habe ich von meinem Professor
Das mag ja sein. Aber er hat dir bestimmt nicht gesagt, dass Du dann ohne weitere Zuweisung der einzelnen Elemente an die Eigenschaften der Klasse irgendwie auf "magische Weise" an die Inhalte kommst, oder?
Martin hat dir es ja auch schon geschrieben, im Konstruktor fehlt dann noch die Zuweisung der Arrayelementinhalte an die Eigenschaften.
Wenn sichergestellt ist, dass das Array sämtliche benötigten Feldinhalte bereitstellt (Anzahl und Reihenfolge im String, der gesplittet wird) kannst Du einfach den anderen Konstruktor, der die einzelnen Eigenschaften als Übergabeparameter annimmt, aufrufen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hi,
wenn der gepostete Code der Klasse CPerson vollständig ist, darf der dritte constructor (mit den p_...-Parametern) auch nicht verwendet werden (ohne Weiterleitung), weil auch dort die Felder wie "sOrt" (Backing für eine Eigenschaft ohne Setter) nicht gesetzt werden.
Ich wiederhole mich daher noch einmal: Sicherstellen, dass der einzig funktionierende constructor bei der Erzeugung jedes CPerson-Objekts verwendet wird und dass dort keine NULL-Werte übergeben werden. Alternativ müsste die ToString-Methode NULL-Werte berücksichtigen/abfangen. Da dies auch für alle anderen Referenzen auf die Eigenschaften (auch außerhalb der Klasse) gilt, ist es wohl sinnvoller im constructor übergebene NULL-Werte in string.Empty o.ä. umzuwandeln.
Und als Tipp für's Erstellen von Programmen, in denen das 'Fehlerfinden' etwas leichter wird, schau Dir mal Eigenschaften mit privaten Settern bzw. readonly Eigenschaften an.
Gruß
Jürgen
-
Hi,
also: Du löscht die beiden 'schlechten' Konstruktoren. Dadurch findest Du (beim nächsten Übersetzen) schon mal die Stellen, an denen Probleme durch deren Aufruf erzeugt werden. Diese Stellen korrigierst Du so, dass dort der verbleibende 'gute' Konstruktor verwendet wird.
Im guten Konstruktor schreibst Du die Zuweisungen wie
this.sVorname = sVorname;
um in
this.sVorname = sVorname ?? string.Empty;
oder in lang
if (sVorname == null) { this.sVorname = string.Empty; } else { this.sVorname = sVorname; }
Gruß
JürgenPS: kein Flaming: wenn Du diese Erklärungen wirklich benötigst, wäre es sicher eine gute Idee ein Buch à la "Die Grundlagen der Programmierung unter besonderer Beröcksichtigung von C#" zu besorgen (ich meine : lesen und durcharbeiten) anstatt gleich mit so einem 'Projekt' loszulegen.
-
Könnte eventuell jemand von euch ein paar Zeilen Code schreiben damit ich mir etwas darunter vorstellen kann was genau ihr meint.
Hallo Brunchek,
ich kann nicht ganz nachvollziehen, was du dir nicht vorstellen kannst.
Wie Martin und Stefan bereits geschrieben haben, liegt das Problem an der fehlenden "Magie" im Konstruktor.
public CPerson(string importline)
Die Exception, die in DisplayItems bzw. bei ToString() geworfen wird, ist nur die Auswirkung der fehlenden Zuordnung, nicht die Ursache.
Ich denke nicht, dass die Zuordnungthis.sVorname = Line[0]; this.sNachname = Line[1]; // usw.
ein großes Problem darstellt (in der Annahme, dass die eingelesenen Zeilen im erwarteten Format vorliegen).
Gruß
Peter
-
Nun ich bin kein Anfänger die Grundlagen beherrsche ich bestens.
Ich will dir wirklich nicht zu nahe treten, aber ich bezweifle doch, dass die Grundlagen wirklich vorhanden sind. Soll aber auch nicht weiter schlimm sein, daher hier mal eine Erklärung des Problems:
while (!Reader.EndOfStream) { string s = Reader.ReadLine(); Add(new CPerson(s)); }
Mit diesem Code rufst Du für jede Zeile in deiner CSV Datei einen der Konstruktoren der Klasse CPerson auf. In deinem Fall den hier:
public CPerson(string importline) { string[] Line = importline.Split(';'); }
Was macht der Konstruktor? Er splittet dein übergebenen String in ein Array. Und dann? Nichts mehr. Nix, Nada, Niente. Die Eigenschaften sVorname, sNachname, ... werden nie gefüllt. Daher sind die beim Auslesen null und es kommt zum Fehler.
Abhilfe kanns Du schaffen, indem Du, wie von Peter beschrieben, die Eigenschaften mit den Werten aus dem Array "Line" besetzt. Achte aber hier darauf, dass sowohl die Anzahl der Elemente als auch die Reihenfolge passen muss. Sonst steht nachher der Nachname in der Strasse, das Alter in der Hausnummer, ...
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Mittwoch, 29. Februar 2012 00:41
-
Hi,
diesmal an alle Helfer: Haltet Ihr den "importline-Konstruktor" wirklich für behaltenswert 1. aus 'architektonischer' Sicht und 2. in Anbetracht der augenscheinlichen Kenntnisse von Brunchek?
Meiner Meinung nach wäre er - selbst wenn er funktionierte - grob fehlerhaftes Design.
Gruß
Jürgen -
Hi Jürgen,
aus "architektonischer" sicht ist es natürlich nicht schon. Den Datenzugriff solte man in einen eigenen Layer Kapseln, ich denk hier würde sich auch eine Factory anbieten.
Was Brunckek Aufgaben stellung angeht, soweit ich es Verstanden habe, ist es Teil einer Übung für die UNI und die Vorgaben kommen vom Professor.
Es wird also nirgendwo im Produktive Code landen, sondern hier soll ein Spezieller Aspekt betrachtet werden (Welcher kann ich gerade nicht erkennen.).
Standard sind meisten bei der OOP sachen wie Vererbung.
Also ich muss gestehen, ich hab schon bei weiteren schlimmere Sachen in Produktive Code gesehen ;)
MFG
Björn
-
Hi Jürgen,
Haltet Ihr den "importline-Konstruktor" wirklich für behaltenswert?
nein
1. aus 'architektonischer' Sicht
2. in Anbetracht der augenscheinlichen Kenntnisse von Brunchek
schon.
Ich sehe das ähnlich wie Palin, dass dies eine Übung ist. Vielleicht geht es dem Professor auch darum, zu sehen, was seine Studenten produzieren, um diese Ergebnisse zu diskutieren und Verbesserungsvorschläge - vielleicht auch Designverbesserungen - herauszuarbeiten.
Das Problem von Brunchek war, dass eine Exception ausgelöst wurde und er nicht wusste, warum. Dieses Frage wurde meiner Meinung nach in diesem Thread hinreichend beantwortet.
Wenn Bruncheck mit dem Design ein Problem haben würde, müsste der Threadtitel "Wie kann ich das Design meines Contactmanagers verbessern" oder so ähnlich heissen. Ich weiss nicht, in welchem Semester Brunchek ist, aber ich denke, dass er sicher noch Gelegenheit bekommt, sich mit Softwarearchitektur auseinandersetzen zu dürfen.Grüße
Peter -
Hi,
1. ich wäre auch mindestens verwundert gewesen
2. Sehe ich anders. Ich habe den Eindruck, dass die schlechten Konstruktoren zur Verkomplizierung und somit ursächlich zum Nicht-Finden des Fehlers beitragen. Und jemandem 'halb' zu helfen in der Annahme, der Rest wird vom Prof mit einer Designdiskussion erledigt, ist nicht mein Ding.
Aber: Ist Dir Brunchek denn jetzt geholfen worden? Läuft Dein Programm zumindest? Oder brauchst Du noch irgenwo Beistand? Dann musst Du aber etwas genauer schreiben, an welchen Stellen Du noch Unterstützung brauchst.
Gruß
Jürgen -
Hi Jürgen,
ich kann dir bei 2 eigentlich nur recht geben.
Das Problem hier ist wo fange ich an und wo höre ich auf.
Wenn ich jemanden "gründlich" Programmieren hier im Forum beibringen will, reichen ja die Grundlagen der OOP nicht. (Ob ich dazu überhaupt in der Lage bin sei mal dahingestellt)
Die Grundprinzipien (z.B. SOLID) gehören ja auch dazu und natürlich die Entwurfsmuster. Antipattern sollte man auch kennen, mehrschichtige Architektur auf jeden Fall. Und Clear Code kann auch nicht schaden.
Und bis zu dem Punkt habe ich noch nichts über das .NET Framework gesagt.
Ich denke du siehst wo das hin geht.
An diesen Punkt möchte ich mal die Leute loben, die hier aktive die Fragen beantworten. Da sie einfach gute Arbeit leisten.
Wenn man sich die meisten Beiträge hier im Forum mal anschaut, gibt es eine Antwort auf die Frage und wenn es nötig ist einen Vorschlag wie man es besser machen kann. (Gab es ja auch hier.)
Wenn die Leute Interesse zeigen, wie man es besser machen kann, wird dann auch meistens weiter geholfen.
In der Hinsicht möchte ich auch direkt erwähnen, das wenn Leute ankommen und einfach Code geschrieben haben wollen.
Sie ihn nicht bekommen, da in gewisser Massen ohne Absprache, die Übereinkunft existiert, den Leuten auch was beibringen zu wollen.
In der Hinsicht noch mal, danke an all die Leute die sich hier aktive in der Foren einbringen.
MFG
Björn
-
Hallo Jürgen,
diesmal an alle Helfer: Haltet Ihr den "importline-Konstruktor" wirklich für behaltenswert 1. aus 'architektonischer' Sicht
als Konstruktor nicht. Als normale Methode wie bspw. FillProperties( string line ) eigentlich schon. Ich mach sowas häufig mit DataRow, ... Allerdings habe ich dort auch über den Namen der Spalte Zugriff auf die einzelnen Elemente der Row. Bei Übergabe eines String, der kommaseparierte Werte enthält, müsste man natürlich noch die Anzahl der Elemente, ggfs. auch deren Werte gegen den Zieldatentyp, ... prüfen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hi.
Falls die frage immer noch aktuell ist: Der Fehler sagt aus, dass eines der Elemente zum Zeitpunkt der Nutzung gleich null ist. Um dich vor diesem Fehler zu schützen müsstest zu zb statt 'Nachname.ToString()' "(Nachname != null) ?' Nachname : "" ' nutzen zudem hast du vor den Variablennamen meist noch ein s oder ein i stehen bei der ToString() Methode (z.B. private string sNachname) aber nicht weshalb es diese variablen wahrscheinlich nicht gibt und sie somit null sein müssen.
Ich hoffe ich konnte helfen dein Problem zu lösen^^
- Bearbeitet DragonSkills99 Dienstag, 17. Mai 2016 15:10