none
NullReferenceException in Events nach XMLSerialize RRS feed

  • Frage

  • Hallo zusammen,

    ich schreibe gerade ein Programm, wo  ich Elemente (die päter grafisch gerendert werden) in eine Liste hinzufüge. Nach dem hinzufügen in der Liste löse ich ein Event aus, um die Grafiken zu aktualisieren.

    Dies funktioniert soweit ganz gut, jedoch wenn ich zuvor gespeicherte Elemente aus einer XML-Datei lade und anschliessend ein Element in der Liste hinzufüge, so bekomme ich immer eine NullReferenceException, wenn ich das Event auslöse.

    Ich füge hier mal den wichtigen Code hinzu:

     

    private void LoadXmlFile_Click(object sender, EventArgs e)

    {

       openFileDialog.ShowDialog();

       if (openFileDialog.FileName == null) return;

      XmlSerializer ser = new XmlSerializer(typeof(MapElements));

      StreamReader sr = new StreamReader(openFileDialog.FileName);

      MapElements newElements= (MapElements)ser.Deserialize(sr);

      sr.Close();

      MapWindow newMap = new MapWindow(newElements.Size);

      newMap.Map = newElements;

      newMap.MdiParent = this;

      newMap.WindowState = FormWindowState.Maximized;

      newMap.Show();

    }

    /* Class: MapWindow */

     

    public MapWindow(Size mapSiize)

    {

      InitializeComponent();

      this.size=mapSize;

      map = new MapElements();

      graph = picMap.CreateGraphics();

      renderer = new RenderEngine(graph); //picMap Events

      initializeEvents();

    }

    // Initializes all events

    private void initializeEvents()

    {

      this.map.creatureAdded += new MapElements.CreatureEventHandler(map_creatureAdded);

    }

    /*Class: MapElements */

     #region Events

     public event CreatureEventHandler creatureAdded;

     #endregion

     public void addCreature(AbstractCreature creature)

     {

        if (!this.creatures.Contains(creature))

            this.creatures.Add(creature);

            creatureAdded(creature);

     }

     

    Laut Debugger ist der Aufruf von creatureAdded == null. Der Parameter creature ist != null.

    Ich hoffe mir kann jemand helfen.

     

    Ciao Kostarsus




    • Bearbeitet Kostarsus Dienstag, 24. Mai 2011 15:52
    Sonntag, 22. Mai 2011 11:48

Antworten

  • Hallo Kostarsus,
    vielen Dank für deine Mail. Ich habe jetzt endlich heute mal die Zeit gefunden, mir dein Projekt mal anschauen zu können. Und ich habe deinen Fehler (durch einfaches Debuggen!!!) gefunden.

    Tipp: Verwende für das Projekt WPF. Sparst dir einen haufen Code und hast mit den WPF deutlich mehr möglichkeiten. Zudem werden die WPF Hardwarebeschleunigt ;) 
    Dein Problem liegt hier:
        private void ladenToolStripMenuItem_Click(object sender, EventArgs e)
        {
          if(openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
           if(openFileDialog.FileName == null) {
             return;
           }
    
           XmlSerializer ser = new XmlSerializer(typeof(MapElements));
           StreamReader sr = new StreamReader(openFileDialog.FileName);
           MapElements newElements = (MapElements)ser.Deserialize(sr);
           sr.Close();
    
           MapWindow newMap = new MapWindow(newElements.Size);
           newMap.Map = newElements;
           newMap.MdiParent = this;
           newMap.WindowState = FormWindowState.Maximized;
           newMap.Show();
          }
        }
    
     Hier musst du übrigens den StreamReader nach dem schliessen noch disposen, sonst erzeugst du ein Memleak. Da ein Reader durchaus auch mal mit eine Exception abrauchen kann, würde ich dir das using statement empfehlen. Das disposed dein Objekt automatisch. Auch dann wenn beim Lesen eine Exception auftritt. Ist also wie ein try-finally Block.

    Nun zu deinem Eigentlichen Problem:

    Du deserialisiert deine Objekte (hängst auch die EventHandler an die Events) und erzeugst danach ein neues MapWindow. Wenn du das erzeugst, erzeugst du natürlich auch den Event neu, andem nun KEIN EventHandler mehr dranhängen.
    Ich hoffe ich konnte dir bei diesem einen Problem helfen, aber du wirst über kurz oder lang noch auf mehr stoßen. Insgesamt wirkt das Projekt leider sehr unstrukturiert, auch im Code. Was aber schon bei kleineren Projekte bereits ein muss ist, da du sonst nach einer bestimmten Zeit/LoCs selbser nicht mehr durchblickst. Fehler wie der von dir Angefragte sind ein Symptom davon.
    Ich hoffe ich konnte dir weiterhelfen. Solltest du noch Fragen haben, dann helfe ich dir natürlich gerne ;)
    Viele Grüße
    Holger M. Rößler

    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
    Sonntag, 29. Mai 2011 08:04

Alle Antworten

  • Hallo Kostarsus,

    sorry, aber aus diesem unformatierten Codewirrwar ist nun wirklich nicht viel zu erkennen. Formatiere doch bitte mal den Code, damit dort mal was zu erkennen ist.

    Nur mal so ins blaue gegriffen: Du prüfst dein Event nicht auf null. Du musst ein Event immer auf null prüfen, bevor du es feuerst.

     

     

    public void Foo() {
     ...
    
     if(this.EinEvent != null) {
     this.EinEvent(this,EventArgs.Empty);
     }
    
     ...
    }
    

     

     

    Ach und noch was! Ich weiss jetzt nicht, ob du deinen Code diesbezüglich für dein Post gekürtzt hast, aber das Graphics Objekt das du dir per picMap.CreateGraphics() erzeugst, solltest du unbedingt Disposen wenn du es nicht mehr benötigst. Sonst erzeugst du jedesmal ein Memleak. ;)

    Solltest du noch fragen haben...immer gerne zu!

    Viele Grüße
    Holger M. Rößler

     


    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++

    Sonntag, 22. Mai 2011 19:51
  • Sorry,

    ich nehme an, dass die Formatierung durch die nachträgliche Bearbeitung des Beitrages verloren ging.

    Dass die Exception ausgelöst wird verstehe ich ja. Du hast Recht, dass das Event == null ist. Was ich aber nicht verstehe ist, wieso das Event== null ist.

    Rufe ich das Fenster ohne vorheriger Deserialisierung auf, so ist das Event gefüllt.

    Die Events werden in beiden Fällen gleich initialisiert (von der Klasse MapWindow). Den einzigen Unterschied den ich sehe, ist dass die MapElemeents anders erzeugt werden.

    Im einen Fall über den normalen new-Operator im anderen Fall eben durch die Deseriialisierung. Ob dies damit zusammenhängt? Und falls ja, gibt es ein Workaround?

     

     

    Ciao Kostarsus

     



    Dienstag, 24. Mai 2011 15:55
  • Hi Kostarsus,

    so ist es schon viel besser :)

    Ein Event ist null, wenn noch keine Delegate also noch kein EventHandler dranhängt, der das Event behandelt. Du wirst die EventHandler nach dem Deserialisieren noch per Hand an die Events ranhängen müssen.

    Viele Grüße
    Holger M. Rößler


    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++

    Dienstag, 24. Mai 2011 16:01
  • Mhm,

     

    also das Delegate habe ich MapElements deklariert (nur vergessen einzufügen ;-)

    public delegate void CreatureEventHandler(AbstractCreature creature);
    

    Die Zuordnung des Events mache ich ja in der Klasse MapWindow (Implementierung steht oben).

    Habe ich noch etwas vergessen?

     

    Ciao Kostarsus

    Dienstag, 24. Mai 2011 16:10
  • Hallo Kostarsus,

    wer horcht denn auf das "creatureAdded" Event?

    Hier nur so als Tipp: Das .net Famework kennt bereits eine Collection, die Änderungen an deren Items per Event meldet. Vielleicht solltest du diese Verwenden, dann ersparst du dir auch den ganzen Zirkus.

    Viele Grüße
    Holger M. Rößler


    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
    Dienstag, 24. Mai 2011 16:36
  • Das MapWindow horcht auf das Event. Dort habe ich ja auch die methode initializeEvents und die Methode hinzugefügt, welche die Aktionen beim Auftritt des Events durchführt.

    Wie gesagt, wenn ich nicht deserialisiere funktionniert alles. Nur nach der Deserialisieerrung ist das Event == null.

    Dienstag, 24. Mai 2011 16:45
  • Hallo Kostarsus,

    hast du die Möglichkeit mir dein Projekt mal zu schicken? Dann kann ich mir das Programm mal RICHTIG ansehen.

    Dann schicke es bitte an holger.roessler@web.de. Danke :)

    Viele Grüße
    Holger M. Rößler


    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
    Mittwoch, 25. Mai 2011 13:14
  • Hallo Kostarsus,
    vielen Dank für deine Mail. Ich habe jetzt endlich heute mal die Zeit gefunden, mir dein Projekt mal anschauen zu können. Und ich habe deinen Fehler (durch einfaches Debuggen!!!) gefunden.

    Tipp: Verwende für das Projekt WPF. Sparst dir einen haufen Code und hast mit den WPF deutlich mehr möglichkeiten. Zudem werden die WPF Hardwarebeschleunigt ;) 
    Dein Problem liegt hier:
        private void ladenToolStripMenuItem_Click(object sender, EventArgs e)
        {
          if(openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
           if(openFileDialog.FileName == null) {
             return;
           }
    
           XmlSerializer ser = new XmlSerializer(typeof(MapElements));
           StreamReader sr = new StreamReader(openFileDialog.FileName);
           MapElements newElements = (MapElements)ser.Deserialize(sr);
           sr.Close();
    
           MapWindow newMap = new MapWindow(newElements.Size);
           newMap.Map = newElements;
           newMap.MdiParent = this;
           newMap.WindowState = FormWindowState.Maximized;
           newMap.Show();
          }
        }
    
     Hier musst du übrigens den StreamReader nach dem schliessen noch disposen, sonst erzeugst du ein Memleak. Da ein Reader durchaus auch mal mit eine Exception abrauchen kann, würde ich dir das using statement empfehlen. Das disposed dein Objekt automatisch. Auch dann wenn beim Lesen eine Exception auftritt. Ist also wie ein try-finally Block.

    Nun zu deinem Eigentlichen Problem:

    Du deserialisiert deine Objekte (hängst auch die EventHandler an die Events) und erzeugst danach ein neues MapWindow. Wenn du das erzeugst, erzeugst du natürlich auch den Event neu, andem nun KEIN EventHandler mehr dranhängen.
    Ich hoffe ich konnte dir bei diesem einen Problem helfen, aber du wirst über kurz oder lang noch auf mehr stoßen. Insgesamt wirkt das Projekt leider sehr unstrukturiert, auch im Code. Was aber schon bei kleineren Projekte bereits ein muss ist, da du sonst nach einer bestimmten Zeit/LoCs selbser nicht mehr durchblickst. Fehler wie der von dir Angefragte sind ein Symptom davon.
    Ich hoffe ich konnte dir weiterhelfen. Solltest du noch Fragen haben, dann helfe ich dir natürlich gerne ;)
    Viele Grüße
    Holger M. Rößler

    Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
    Sonntag, 29. Mai 2011 08:04