.
Anmeldung | Registrieren | Hilfe
in Suchen

Invokation of polymorphic field-like event?

Letzter Beitrag 23. Jan 2010 16:48 von Rainer Hilmer. 5 Antworten.
Seite 1 von 1 (6 Treffer)
Beiträge sortieren: Zurück Weiter
  • 22. Jan 2010 18:51

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 950
    • Punkte 14.310

    Invokation of polymorphic field-like event?

    Hallo,
    ich habe eine abstrakte Klasse mit einem abstrakten Event. Wenn ich das Event in einer Subklasse überschreibe, bemerkt Resharper "Invokation of polymorphic field-like event". Was bedeutet das und: ist das verboten? Ich habe im Internet nichts darüber gefunden.
    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 22. Jan 2010 19:23 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.140

    Invokation of polymorphic field-like event?

    Antworten
    Hallo Reiner,

    folgendes ist meine Vermutung, kann es hier wegen Ermangelung von ReSharper nicht testen:
    - Wenn die abstrakte Basisklasse ein Event deklariert, dann generiert der Compiler die Accessor Methoden (Die Add und Remove Methoden) für die Basisklasse
    - Eine Ableitung, die das Event überschreibt, und dann auslöst wird höchstwahrscheinlich die Accessormethoden aus der Basisklasse aufrufen, was wahrscheinlich unerwünscht ist

    Laut MSDN kann man das Event in der Basisklasse explizit mit dem Schlüsselwort abstract deklarieren, dann baut der Compiler keine Accesor Methoden dafür, eventuell löst das Dein Problem?

    Microsoft predigt aber da ein anderes Pattern. Das "OnMyEvent"-Pattern, das so aussieht:
        /// <summary>
        /// Abstrakte Klasse, die das Microsoft Event Pattern implementiert.
        /// </summary>
        public abstract class AbstractEventClass
        {
            /// <summary>
            /// Die Deklaration des Events.
            /// </summary>
            public event EventHandler<EventArgs> MyEvent;
    
            /// <summary>
            /// Eine geschützte Methode, die letztlich das Ereignis auslöst.
            /// </summary>
            /// <param name="args">Ereignisparameter, die übergeben werden sollen.</param>
            protected virtual void OnMyEvent(EventArgs args)
            {
                if (MyEvent != null)
                {
                    MyEvent(this, args);
                }
            }
        }


    Die Ableitung sähe dann so aus:
        /// <summary>
        /// Eine Ableitung der <see cref="T:AbstractEventClass"/> Klasse.
        /// </summary>
        public class ConcreteEventClass : AbstractEventClass
        {
            /// <summary>
            /// Flag, das angibt, ob das Ereignis unterdrückt werden soll.
            /// </summary>
            private bool suppressEvent = true;
    
            /// <summary>
            /// Methode, die das Ereignis <see cref="E:MyEvent"/> auslösen wird,
            /// falls es mit dem Flag <see cref="T:suppressEvent"/> nicht unterdrückt wird.
            /// </summary>
            /// <param name="args">Ereignisparameter, die übergeben werden sollen.</param>
            protected override void OnMyEvent(EventArgs args)
            {
                if (!suppressEvent)
                {
                    base.OnMyEvent(args);
                }
            }
        }


    Ich denke mit diesem Pattern sind alle Möglichkeiten offen, oder?

    Grüße
    Timo
    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
  • 23. Jan 2010 11:57 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 950
    • Punkte 14.310

    Invokation of polymorphic field-like event?

    Antworten

    Hallo Timo,
    danke für den Tip. Ich habe das MSDN-Beispiel mal leicht verbogen weil man sich ausmalen muß daß man an die geschützte MyEvent-Methode nur über einen Umweg herankommt. In meinem Fall dient das Event als Überwachung für ein Property. Ich weiß, ich hätte auch INotifyPropertyChanged implementieren können, aber das Ding gefällt mir nicht so recht, weil das Event eben nur "PropertyChanged" heißt und ausserhalb einer Komponente dadurch wenig aussagekräftig ist (CCD). Nachfolgend ein kleines Demo:

    using System;
    
    
    namespace AbstractEvent
    {
       class Program
       {
          static void Main()
          {
             Endschalter endschalterOben = new EndschalterOben();
             endschalterOben.ContactChanged += EndschalterOben_ContactChanged;
    
    
             Endschalter endschalterUnten = new EndschalterUnten();
             endschalterUnten.ContactChanged += EndschalterUnten_ContactChanged;
    
    
             endschalterOben.SetContact(true);
             endschalterUnten.SetContact(true);
             endschalterOben.SetContact(false);
    
    
             // Verhindert das selbsttätige Schließen des Konsolenfensters.
             Console.WriteLine("\nPress any key to terminate the program.");
             Console.ReadKey();
          }
    
    
          private static void EndschalterOben_ContactChanged(object sender, EventArgs e)
          {
             if(((Endschalter)sender).Contact)
                Console.WriteLine("Endschalter oben hat Kontakt.");
             else
                Console.WriteLine("Endschalter oben hat keinen Kontakt.");
          }
    
    
          private static void EndschalterUnten_ContactChanged(object sender, EventArgs e)
          {
             if(((Endschalter)sender).Contact)
                Console.WriteLine("Endschalter unten hat Kontakt.");
             else
                Console.WriteLine("Endschalter unten hat keinen Kontakt.");
          }
       }
    
    
       public abstract class Endschalter
       {
          public event EventHandler ContactChanged;
    
    
          private bool contact;
          public virtual bool Contact
          {
             get { return contact; }
             protected set
             {
                if(contact == value)
                   return;
                contact = value;
                if(ContactChanged != null)
                   ContactChanged(this, new EventArgs());
             }
          }
    
    
          public void SetContact(bool state)
          {
             Contact = state;
          }
       }
    
    
       public class EndschalterOben : Endschalter
       {
          #region Overrides of Endschalter
    
    
          private bool contact;
          public override bool Contact
          {
             get { return contact; }
             protected set
             {
                if(contact == value)
                   return;
                contact = value;
                base.Contact = contact;
             }
          }
    
    
          #endregion
       }
    
    
       public class EndschalterUnten : Endschalter
       {
          #region Overrides of Endschalter
    
    
          private bool contact;
          public override bool Contact
          {
             get { return contact; }
             protected set
             {
                if(contact == value)
                   return;
                contact = value;
                base.Contact = contact;
             }
          }
    
    
          #endregion
       }
    }
    /* Output:
    Endschalter oben hat Kontakt.
    Endschalter unten hat Kontakt.
    Endschalter oben hat keinen Kontakt.
    */

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 23. Jan 2010 12:15 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 950
    • Punkte 14.310

    Invokation of polymorphic field-like event?

    Der Witz an der Sache: Kommentiere ich das abgeleitete Property aus beiden Subklassen aus (in diesem Fall bleiben nur leere Klassenrümpfe übrig), funktioniert es genau so, ohne daß ich eine Zeile Code ändern müßte!

    using System;
    
    
    namespace AbstractEvent
    {
       class Program
       {
          static void Main()
          {
             Endschalter endschalterOben = new EndschalterOben();
             endschalterOben.ContactChanged += EndschalterOben_ContactChanged;
    
    
             Endschalter endschalterUnten = new EndschalterUnten();
             endschalterUnten.ContactChanged += EndschalterUnten_ContactChanged;
    
    
             endschalterOben.SetContact(true);
             endschalterUnten.SetContact(true);
             endschalterOben.SetContact(false);
    
    
             // Verhindert das selbsttätige Schließen des Konsolenfensters.
             Console.WriteLine("\nPress any key to terminate the program.");
             Console.ReadKey();
          }
    
    
          private static void EndschalterOben_ContactChanged(object sender, EventArgs e)
          {
             if(((Endschalter)sender).Contact)
                Console.WriteLine("Endschalter oben hat Kontakt.");
             else
                Console.WriteLine("Endschalter oben hat keinen Kontakt.");
          }
    
    
          private static void EndschalterUnten_ContactChanged(object sender, EventArgs e)
          {
             if(((Endschalter)sender).Contact)
                Console.WriteLine("Endschalter unten hat Kontakt.");
             else
                Console.WriteLine("Endschalter unten hat keinen Kontakt.");
          }
       }
    
    
       public abstract class Endschalter
       {
          public event EventHandler ContactChanged;
    
    
          private bool contact;
          public bool Contact
          {
             get { return contact; }
             protected set
             {
                if(contact == value)
                   return;
                contact = value;
                if(ContactChanged != null)
                   ContactChanged(this, new EventArgs());
             }
          }
    
    
          public void SetContact(bool state)
          {
             Contact = state;
          }
       }
    
    
       public class EndschalterOben : Endschalter { }
    
    
       public class EndschalterUnten : Endschalter { }
    }
    /* Output:
    Endschalter oben hat Kontakt.
    Endschalter unten hat Kontakt.
    Endschalter oben hat keinen Kontakt.
    */

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
  • 23. Jan 2010 15:36 Antwort zu

    • Timo Rehl
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 05. Mai 2009
    • Wald-Michelbach
    • Beiträge 591
    • Punkte 10.140

    Invokation of polymorphic field-like event?

    Hallo Rainer,

    naja, um es mal einfach auszudrücken: Wenn Du in der überschriebenen Methode/Eigenschaft das Gleiche implementierst wie in der Basisklasse, was soll sich am Verhalten dann auch ändern?

    Deshalb mein oben illustriertes Beispiel. Es ist nicht unmöglich, aber mit etwas fadem Beigeschmack, wenn man die Events (Delegates) versucht "zweckzuemtfremden". Das Überschreiben und das ändern des Verhaltens relaisiert man dann lieber mit Methoden.

    In Deinem Beispiel nimmst Du den Setter. Aber auch dort würde ich hergehen und eine separate Methode dafür verwenden:
    public abstract class Endschalter
       {
          public event EventHandler ContactChanged;
    
    
          private bool contact;
          public bool Contact
          {
             get { return contact; }
             protected set
             {
                if(contact == value)
                   return;
                contact = value;
                OnContactChanged(new EventArgs());
             }
          }
    
    
          public void SetContact(bool state)
          {
             Contact = state;
          }
    
          protected virtual void OnContactChanged(EventArgs e)
          {
                if(ContactChanged != null)
                   ContactChanged(this, e);
          }
       }


    Warum würde ich das so machen? Vielleicht gibt es auch andere Szenarien innerhalb der Klasse, die dazu führen, dass sich der Zustand der Variablen contact ändern?
    Viel wichtiger ist es noch bei abgeleiteten Klassen. Diese möchten unter Umständen ein eigenes geändertes Verhalten implementieren. Da fände ich es flexibler, wenn man das Ändern der Variablen von der Ereignisauslösung trennt. Ansonsten hat die Ableitung keine Chance das Ändern der Variablen von dem Ereignis zu trennen.

    Hier gibt es z.B. auch diverse Besipiele hierfür. Nimm mal ein GUI Element, das sich in der Initialisierungsphase befindet. Dort passieren in der Regel sehr viele Zustandsänderungen, man möchte sicherlich dann nicht jedes Mal eine Ereignisauslösung haben...

    Aber letztendlich musst Du wissen wie das gewünschte Verhalten sein soll, von daher verteufele ich Deine Lösung sicherlich nicht.

    Grüße
    Timo
    - theres no place like 127.0.0.1 -
    • IP-Adresse ist Registriert
  • 23. Jan 2010 16:48 Antwort zu

    • Rainer Hilmer
    • Top 10 Mitwirkender
      Männlich
    • Registriert am 22. Jan 2008
    • Braunschweig
    • Beiträge 950
    • Punkte 14.310

    Invokation of polymorphic field-like event?

    Timo Rehl:

    naja, um es mal einfach auszudrücken: Wenn Du in der überschriebenen Methode/Eigenschaft das Gleiche implementierst wie in der Basisklasse, was soll sich am Verhalten dann auch ändern?

    Stimmt, mein Beispiel war wohl etwas zu simpel.

    Gruß,
    Rainer
    • IP-Adresse ist Registriert
Seite 1 von 1 (6 Treffer)

WPF Forum | ASP.NET Forum | ASP.NET MVC Forum | Silverlight Forum | Windows Phone 7 Forum | SharePoint Forum | Dotnet Jobs | Dotnet Termine | Developer Blogs | Dotnet News

Das Team | Regeln | Impressum