NullReferenceException beim Feuern des Events

Mar 1, 2010 at 1:19 PM

Hallo Ralf,
ich wollte eben deinen ComponentBinder an einem ganz simplen Beispiel ausprobieren. Leider kommt es beim Event zu einer NullReferenceException (das Event wird offenbar nicht verbunden).
Hier ist der Beispielcode:

class Program
{
      static void Main()
      {
         IOutputConnector lampSwitch = new LampSwitch();
         IInputConnector lamp = new Lamp();;
         // Funktioniert:
         //lampSwitch.OnSwitch += lamp.ProcessInput;

         // Funktioniert nicht! Das Event wird nicht verbunden.
         new ComponentBinder().Bind(new object[] { lampSwitch, lamp });         

         ((LampSwitch)lampSwitch).Input(true);
         ((LampSwitch)lampSwitch).Input(false);;
      }
}

//--- Interfaces ------------------------------

   public interface IInputConnector
   {
      void ProcessInput(bool status);
   }

   public interface IOutputConnector
   {
      event Action<bool> OnSwitch;
   }

//---------------------------------------------

   public class LampSwitch : IOutputConnector
   {
      public void Input(bool status)
      {
         // Hier kommt es zu einer NullReferenceException!
         OnSwitch(status);
      }

      #region Implementation of IOutputConnector

      public event Action<bool> OnSwitch;

      #endregion
   }

//---------------------------------------------

   public class Lamp : IInputConnector
   {
      public LampStatus LampStatus { get; private set; }

      #region Implementation of IInputConnector

      public void ProcessInput(bool status)
      {
         LampStatus = status ? LampStatus.On : LampStatus.Off;
         Console.WriteLine("Lamp status = {0}", LampStatus);
      }

      #endregion
   }

   public enum LampStatus
   {
      Off = 0,
      On = 1
   }
Mar 3, 2010 at 8:39 AM

Hallo Rainer,

die Namenskonvention sieht offenbar vor der Lampe ein "ProcessSwitch" zu spendieren passend zu "OnSwitch" :

"ComponentBinder.CheckIfPinsMatch" prüft die Gleichheit der Namensteile ohne den Präfix ( InputPin.PinName==OutputPin.PinName ).

Damit verhindert Ralf mindestens die Verkuppelung der Kühlwasserquelle mit dem Schwachstromverbraucher: OnSprudel passt nicht zu ProcessBlitzschlag.

Ohne das jetzt im Code zu überprüfen wäre bei derart unterschiedlicher Bedeutung schon der Vergleich inkompatibler Parameter ein Ausschlusskriterium beim Binden.

Wie dann aber die Transistoren oder ähnliche Mehrbeiner die ja immer wieder in Ralfs Motiviergeschichten vorkommen ihre Beinchen verdrahten lassen können wo der Parameter wohl immer so was wie Ampere verteilt und die sinnvolle Verknüpfung der Strömlinge der schöpferischen Fantasie des Lötkolbens überlassen ist, wird mit diesem Bindungsmechanismus wohl noch nicht darstellbar.

Oder es bedarf tatsächlich der expliziten Lötstelle die mit eigenen Pins den IchgebeStromPin mit dem/den IchnehmeStromPin(s) verbandelt die von den vielen gleichartigen Pins der Stromnehmerkomponente wirklich gemeint sind. Zumal der Stromgeber gar nicht wissen kann welche exotischen Stromnehmerpins da in Zukunft ProcessInput sagen wollen. Was jetzt nicht gegen das Konzept spricht !! Hier werden auch die mechanischen Komponenten-Bilder eher zum Hindernis.

Und wenn das alles SO denn doch nicht aufgehen sollte ist die Implementierung immerhin ein geiles Stück Code .

Mar 3, 2010 at 9:03 AM

Hallo Frank,

tatsächlich, mit ProcessSwitch funktioniert es. Danke für den Tip.

Ich finde, hier müßte noch verbessert werden. Statt einfach nichts zu machen, sollte eine aussagekräftige Exception geschmissen werden (z.B. "ProcessSwitch excpected").
Dieser Fall ist ein gutes Beispiel für alle, die Exceptions im Code für wenig sinnvoll halten. Ich denke dabei an die Diskussion in diesem Blogartikel -> http://dotnet-forum.de/blogs/nicofranze/archive/2009/12/07/restriktiv-vs-robust.aspx

Gruß,
Rainer Hilmer