[C#] Meerdere listeners in 1 maal notifyen?

Pagina: 1
Acties:
  • 205 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don't fear

Topicstarter
Tweakers,

Na veel gelezen te hebben over .Net 2005 (en nu natuurlijk ook 2008) ben ik fanatiek aan de slag gegaan met C#. Heerlijke taal, feeling van Java. Afijn, nu zit ik met het volgende dilemma.

Ik heb een aantal clients die een interface implemteren (zie ListenerInterface). Deze dienen te luisteren naar de class Thing. Wanneer de methode fireFooEvent wordt aangeroepen, wordt ook van iedere listener de fooEvent methode aangeroepen. Dit geldt ook voor het fireBar Event. Alles werkt naar behoren. Echter moet ik nu voor ieder event dat gefired moet kunnen worden door alle clienten lopen (met de foreach).

De vraag:
Is het ook mogelijk om één methode te schrijven waaraan je meegeeft welke methode van de client moet worden aangeroepen, en met welke argumenten dit moet gebeuren?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public Class Thing {
    private ArrayList listeners;
        private int a;
        private string b;

    public Thing()
    {
        listeners = new ArrayList();
    }

    public void addListener(ListenerInterface listener)
    {
        listeners.Add(listener);
    }

    public void removeListener(ListenerInterface listener)
    {
        listeners.Remove(listener);
    }
    
    public void fireFooEvent(){
        foreach (ListenerInterface l in listeners)
        {
            I.fooEvent(a);
        }
    }
    
    public void fireBarEvent(){
        foreach (ListenerInterface l in listeners)
        {
            I.barEvent(b);
        }
    }
}


public Interface ListenerInterface {

    void fooEvent(int a);

    void barEvent(string b);
}

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 01:58
Ik ken geen C#, maar ik vond op MSDN iets over het implementeren van het Observer Pattern (wat je hier hebt geïmplementeerd) in C#, door middel van delegates en events: http://msdn2.microsoft.com/en-us/library/ms954621.aspx. Misschien dat je er wat mee kunt. :)

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Je hebt het precies verkeerd om gedaan :) Een listener moet niet bekend zijn bij degene die beluisterd wordt, dat is de truuk. In .NET gebruik je events om listeners te laten luisteren. Dus Thing heeft een event en alle listeners binden aan dat event. In THing kijk je of het event null is, zo nee dan raise je het event. Alle bound listeners krijgen dan een call (synchroon, willekeurige volgorde). Listeners roepen dus niet Thing aan om zich aan te melden, ze binden zelf aan het event.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don't fear

Topicstarter
EfBe schreef op zaterdag 19 januari 2008 @ 09:58:
Je hebt het precies verkeerd om gedaan :) Een listener moet niet bekend zijn bij degene die beluisterd wordt, dat is de truuk. In .NET gebruik je events om listeners te laten luisteren. Dus Thing heeft een event en alle listeners binden aan dat event. In THing kijk je of het event null is, zo nee dan raise je het event. Alle bound listeners krijgen dan een call (synchroon, willekeurige volgorde). Listeners roepen dus niet Thing aan om zich aan te melden, ze binden zelf aan het event.
Dat klopt er moet eigenlijk nog een main bij:

C#:
1
2
3
4
5
6
7
8
9
10
        static void Main(string[] args)
        {
            ListenerInterface l1 = new XListener();
            ListenerInterface l2 = new XListener();
            Thing t = new Thing();
            t.addListener(l1);
            t.addListener(l2);
            t.fireFooEvent();
            t.fireBarEvent();
        }

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don't fear

Topicstarter
kingmuze schreef op zaterdag 19 januari 2008 @ 11:39:
[...]


Dat klopt er moet eigenlijk nog een main bij:

C#:
1
2
3
4
5
6
7
8
9
10
        static void Main(string[] args)
        {
            ListenerInterface l1 = new XListener();
            ListenerInterface l2 = new XListener();
            Thing t = new Thing();
            t.addListener(l1);
            t.addListener(l2);
            t.fireFooEvent();
            t.fireBarEvent();
        }
Hmm ik denk dat ik je verkeerd begrijp. Maar zoals JaapJan zegt bedoel ik inderdaad het observer pattern. Van alle listeners moet op een bepaald moment een bepaalde methode met de bijbehorende argumenten aangeroepen worden.

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • KoW
  • Registratie: Juli 2001
  • Laatst online: 17-08-2022

KoW

Parse parsed te veel

Zelf ben ik ook een tijdje terug met C# begonnen.

Maar waarom probeer je niet iets als:
C#:
1
t.fireFooEvent+= new System.EventHandler(iets.FooListener);

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Het lijkt erop dat je java aan het programmeren bent in C# :) De standaardmanier om events te raisen en naar events te luisteren gebeurt in C# (zoals KoW hierboven al aangeeft) d.m.v. het "event" keyword.

E.e.a. staat hier uitgelegd: http://msdn2.microsoft.co...rary/9aackb16(VS.80).aspx

In het kort komt het erop neer dat je een delegate definieert die omschrijft hoe je event-methode eruit ziet (net zoals je in java in je listener interface zou doen). Vervolgens definieer je op de class die de events gaat afvuren een "event" van het type van je delegate, zodat listeners zich op dat event kunnen abonneren.
Dit abonneren kan altijd door meerdere listeners gedaan worden, en het afvuren van events gebeurt ook in een keer naar alle listeners. Dit gedrag is standaard voor events, hier hoef je zelf niets extra's voor te programmeren.

Acties:
  • 0 Henk 'm!

  • SKiLLa
  • Registratie: Februari 2002
  • Niet online

SKiLLa

Byte or nibble a bit ?

Gewoon ff googlen op C# publisher subscriber pattern example of zoiets.

Het idee is inderdaad dat de alle subscribers zichzelf "subscriben" aan het event dat de "publisher" kan publiceren. Als de "publisher" vervolgens het event afvuurt, worden alle "subscribers" geinformeerd.

'Political Correctness is fascism pretending to be good manners.' - George Carlin


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 01:58
MrBucket schreef op zaterdag 19 januari 2008 @ 13:47:
Het lijkt erop dat je java aan het programmeren bent in C# :) De standaardmanier om events te raisen en naar events te luisteren gebeurt in C# (zoals KoW hierboven al aangeeft) d.m.v. het "event" keyword.
Hij programmeert gewoon het pattern uit zoals beschreven door de GoF. Als je dan zegt dat hij Java programmeert in C#, dan vind ik dat wel een béétje kort door de bocht. :)
SKiLLa schreef op zaterdag 19 januari 2008 @ 13:55:
Gewoon ff googlen op C# publisher subscriber pattern example of zoiets.

Het idee is inderdaad dat de alle subscribers zichzelf "subscriben" aan het event dat de "publisher" kan publiceren. Als de "publisher" vervolgens het event afvuurt, worden alle "subscribers" geinformeerd.
De officiële naam is dus het Observer Pattern. :)

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Nog even een versimpeld voorbeeld van events en delegates:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
   // Delegate declaration. Defines the method signature for the alarm event handler.
   public delegate void AlarmEventHandler(object sender, EventArgs e);

   // The Alarm class that raises the alarm event.
   public class AlarmClock
   {
      // The event member that is of type AlarmEventHandler.
      public event AlarmEventHandler Alarm;

      // Fires the Alarm event to all registered listeners.
      public void Fire()
      {
         if (Alarm != null)
         {
            // Invokes the delegates. 
            Alarm(this, new EventArgs());
         }
      }
   }

   public class TheListener
   {
      public void Go()
      {
         //Create an AlarmClock and register the "WakeUp" method as a listener 
         //to the alarm event.
         AlarmClock alarmClock = new AlarmClock();
         alarmClock.Alarm += new AlarmEventHandler(this.WakeUp);

         //Have the AlarmClock fire the Alarm event. Our wake-up method will be called.
         alarmClock.Fire();
      }

      //This method is registered as a listener to the Alarm event.
      //Note that it has the same signature as described by the AlarmEventHandler
      public void WakeUp(object sender, EventArgs e)
      {
         Console.WriteLine("I'm awake!");
      }
   }
Jaap-Jan schreef op zaterdag 19 januari 2008 @ 14:07:
[...]
Hij programmeert gewoon het pattern uit zoals beschreven door de GoF. Als je dan zegt dat hij Java programmeert in C#, dan vind ik dat wel een béétje kort door de bocht. :)
Ja, ik weet het, ik ben bekend met dit pattern. Maar waar in java dit de manier is om event handling te implementeren, is er bij .NET voor een andere constructie gekozen, nl. die van delegates en events.

Acties:
  • 0 Henk 'm!

  • SKiLLa
  • Registratie: Februari 2002
  • Niet online

SKiLLa

Byte or nibble a bit ?

Jaap-Jan schreef op zaterdag 19 januari 2008 @ 14:07:
[...]
De officiële naam is dus het Observer Pattern. :)
Nee hoor, beiden zijn equivalente "officiële" namen; veel design patterns hebben meerdere namen ...

'Political Correctness is fascism pretending to be good manners.' - George Carlin


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don't fear

Topicstarter
SKiLLa schreef op zaterdag 19 januari 2008 @ 14:25:
[...]


Nee hoor, beiden zijn equivalente "officiële" namen; veel design patterns hebben meerdere namen ...
Yes, die constructie ben ik inderdaad vaker tegen gekomen. Nu is het bij deze constructie wel verplicht object sender en EventArgs e te gebruiken. Is het ook mogelijk andere variabelen hiervoor te defineren. Anders moet ik voor iedere hoeveelheid en type argumenten een andere afgeleide van de EventArgs maken.

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 01:58
SKiLLa schreef op zaterdag 19 januari 2008 @ 14:25:
[...]


Nee hoor, beiden zijn equivalente "officiële" namen; veel design patterns hebben meerdere namen ...
Ik heb eigenlijk geen zin om mijn gelijk te krijgen op dit soort gemierrenneuk, maargoed. ;)

De officiële naam is (volgens de GoF die ik er op nageslagen heb) Observer. Alternatieve (opgegeven onder 'Also known as') namen zijn 'dependents' en 'publish/ subscribe'). Alle patterns hebben één officiële naam, maar ze hebben inderdaad vaak meerdere namen, al zijn die niet officieeel.

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
Laat ons hier nu niet miereneuken over dé naam van het pattern of de manier waarop het moet geimplementeerd worden.

De topicstarter heeft het idd geimplementeerd zoals het in het GoF boek geschreven staat, maar in .NET is het idd makkelijker om eenzelfde functionaliteit te implementeren mbhv events / delegates.
Het voordeel met die methode is zoals EfBe al aandraagt: je listener is 'niet rechtstreeks' bekend bij je 'subject'.

Om een antwoord te geven op de vraag van de TS:
Als je het zo wilt blijven doen (en dus geen gebruikt wilt maken van events), dan is het denk ik wel mogelijk mbhv reflection, maar dan verneuk je je model wel een beetje.

[ Voor 20% gewijzigd door whoami op 19-01-2008 15:42 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • SKiLLa
  • Registratie: Februari 2002
  • Niet online

SKiLLa

Byte or nibble a bit ?

Dat de "publisher-subscriber" niet de 1ste benaming is van het pattern, maak het niet minder "officieel". Tijden veranderen ook, vergelijk een uitgave van 10 jaar geleden maar eens met een gloednieuwe, is een wereld van verschil (weet ik uit ervaring). De tijd zal leren wat de dominante benaming zal worden.

Persoonlijk vind ik de publisher/subscriber benaming veel sprekender & beter aansluiten bij de C# implementatie ervan, maar da's imho.

PS:
Yes, die constructie ben ik inderdaad vaker tegen gekomen. Nu is het bij deze constructie wel verplicht object sender en EventArgs e te gebruiken. Is het ook mogelijk andere variabelen hiervoor te defineren. Anders moet ik voor iedere hoeveelheid en type argumenten een andere afgeleide van de EventArgs maken.
Je kan inderdaad je eigen type "EventArgs" definieeren en gebruiken, net zoals b.v. "OnClick" events afgeleide "EventArgs" gooien ... krijg je dus iets als "object sender, MyOwnTypeEventArgs args"

[ Voor 37% gewijzigd door SKiLLa op 19-01-2008 15:55 ]

'Political Correctness is fascism pretending to be good manners.' - George Carlin


Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
kingmuze schreef op zaterdag 19 januari 2008 @ 15:09:
[...]


Yes, die constructie ben ik inderdaad vaker tegen gekomen. Nu is het bij deze constructie wel verplicht object sender en EventArgs e te gebruiken. Is het ook mogelijk andere variabelen hiervoor te defineren. Anders moet ik voor iedere hoeveelheid en type argumenten een andere afgeleide van de EventArgs maken.
Hmm, het is niet echt verplicht, het is meer een soort van afspraak waar het .NET framework zich aan houdt. En het wordt gezien als good practice als je eigen code zich daar ook aan houdt, omdat het geheel er dan uniform uitziet. Maar de compiler dwingt de signature "void myEvent(object sender, EventArgs e)" niet af.

Je kunt dus rustig een event met de signature "float myEvent(DateTime date, string name)" maken.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
kingmuze schreef op zaterdag 19 januari 2008 @ 15:09:
[...]


Yes, die constructie ben ik inderdaad vaker tegen gekomen. Nu is het bij deze constructie wel verplicht object sender en EventArgs e te gebruiken. Is het ook mogelijk andere variabelen hiervoor te defineren. Anders moet ik voor iedere hoeveelheid en type argumenten een andere afgeleide van de EventArgs maken.
Ja, je moet maar eens kijken naar EventHandler where T : EventArgs
Je zal dus idd je eigen EventArgs class moeten maken die inherit van 'EventArgs', maar dat is nu ook het einde van de wereld niet.
Door de generieke 'EventHandler' ben je toch al verlost van het feit dat je een specifieke delegate moet maken.
Zowiezo moet je eventhandler voldoen aan de signature die beschreven wordt in de delegate.
Hmm, het is niet echt verplicht, het is meer een soort van afspraak waar het .NET framework zich aan houdt. En het wordt gezien als good practice als je eigen code zich daar ook aan houdt, omdat het geheel er dan uniform uitziet. Maar de compiler dwingt de signature "void myEvent(object sender, EventArgs e)" niet af.

Je kunt dus rustig een event met de signature "float myEvent(DateTime date, string name)" maken.
Hmm .... Dit kan enkel en alleen als je je eigen delegate gaat maken.
Als je de EventHandler wilt gebruiken, dan zal je aan die signature ( void ( object, EventArgs) ) moeten voldoen.

[ Voor 26% gewijzigd door whoami op 19-01-2008 16:34 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
whoami schreef op zaterdag 19 januari 2008 @ 16:33:
[...]

Ja, je moet maar eens kijken naar [html]<code>EventHandler<T> where T : EventArgs</code>[/]
Je zal dus idd je eigen EventArgs class moeten maken die inherit van 'EventArgs', maar dat is nu ook het einde van de wereld niet.
Door de generieke 'EventHandler' ben je toch al verlost van het feit dat je een specifieke delegate moet maken.
Zowiezo moet je eventhandler voldoen aan de signature die beschreven wordt in de delegate.


[...]
Hmm .... Dit kan enkel en alleen als je je eigen delegate gaat maken.
Als je de EventHandler wilt gebruiken, dan zal je aan die signature ( void ( object, EventArgs) ) moeten voldoen.
Hmm, ik ben niet anders gewend dan m'n eigen delegates te definieren... (vroegah, in .NET 1.1 bestond er nog geen generic EventHandler). En hoewel ik zeker niet wil promoten om af te wijken van de "void myEvent(object sender, EventArgs e)" signature, denk ik wel dat je het met me eens bent dat zo'n delegate heel wat minder werk is om te schrijven dan je eigen EventArgs afgeleiden :)

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
Idd ( heb ook nog een .NET 1.1 project lopen .... ).
Maar, je eigen EventArgs class schrijven is misschien wat meer werk, maar zo complex is het ook niet (niet dat je eigen delegate schrijven complex is).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
Wat is het nut van het schrijven van een eigen class als een integer parameter bijvoorbeeld voldoende is?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don&#039;t fear

Topicstarter
double post (door internet problemen)

[ Voor 88% gewijzigd door kingmuze op 20-01-2008 10:49 ]

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • kingmuze
  • Registratie: Februari 2003
  • Laatst online: 24-10-2024

kingmuze

so don&#039;t fear

Topicstarter
farlane schreef op zondag 20 januari 2008 @ 00:31:
Wat is het nut van het schrijven van een eigen class als een integer parameter bijvoorbeeld voldoende is?
Inderdaad. En ik snap dat het meer generiek is. Maar ik kan mij bijna niet voorstellen dat dit het enige is wat men nastreeft.

[gvr]muze[nl] says: fear is the mind killer


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
farlane schreef op zondag 20 januari 2008 @ 00:31:
Wat is het nut van het schrijven van een eigen class als een integer parameter bijvoorbeeld voldoende is?
Waar zou jij die int dan indoen bij EventArgs? Die heeft geen mogelijkheid daartoe. En ookal zou het kunnen, dan is het knoeien, want je eventhandler krijgt een EventArgs binnen en dan is het in dat geval ineens zo dat een parameter daarin een int is en dat het ABC voorstelt. Wanneer je dan een eigen eventargs maakt is het duidelijker.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
farlane schreef op zondag 20 januari 2008 @ 00:31:
Wat is het nut van het schrijven van een eigen class als een integer parameter bijvoorbeeld voldoende is?
Het is
a) niet netjes
b) niet mogelijk, want de signature van EventHandler<T> ziet er zo uit:
code:
1
2
3
4
public delegate void EventHandler<TEventArgs> (
    Object sender,
    TEventArgs e
) where TEventArgs : EventArgs

int is geen EventArgs.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
farlane schreef op zondag 20 januari 2008 @ 00:31:
Wat is het nut van het schrijven van een eigen class als een integer parameter bijvoorbeeld voldoende is?
De gedachte achter de EventArgs is (volgens mij) dat het beter is om al je event-parameters in een object te stoppen, omdat je dan maar 1 reference hoeft door te geven naar je listeners. Zou je al je event-parameters als argumenten aan je event-functie doorgeven, dan zullen deze voor elke call naar een listener opnieuw gekopieerd moeten worden.

Bovendien is het met een EventArgs object ook mogelijk om inheritance te gebruiken binnen je event argumenten, iets wat niet direct mogelijk is als je elke parameter als los argument meegeeft.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 11-09 12:01
Erm, de TS maakt toch zelf een event/delegate aan ? Dat het een System.Eventhandler zou moeten zijn wordt hier ergens gesuggereerd maar dat hoeft helemaal niet.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1