Jump to content
  • Advertisement
Sign in to follow this  
ChristianPena

[.net] C# - Events vs Traditional Callback Methods

This topic is 4855 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I am working on a messaging system to centralize all text ouput in my game. The scheme that I have will likely seem very traditional: I have a central OutputManager. All objects that want to display output have a reference to that object. They add messages to the OutputManager. Once per frame, the OutputManager dispatches all messages to OutputListeners. When I was doing this in C++, I managed a list of OutputListeners through which I iterated and dispatched the appropriate events. The messages are dispatched on one or more of the 3 available channels: Public, Log, Debug. The OutputListeners subscribe to channels and the OutputManager ensures that the listeners only receive the messages they subscribed to. In C#, I was considering having the OutputManager have 3 public events to raise for each message type. OutputListeners would be registered by having their AddOutput method be a handler for each of the events to which they subscribe. So if a message is on the queue for Public, when it is dispatched, the OutputManager simply invokes the PublicOutputDispatched(string message) event which is then passed on to the interested OutputListeners. I could also just do what I was doing in C++ and store a list of OutputListeners. I haven't perfected the scheme yet, and I would like to have this be more flexible, but for now, I would certainly accept it. I would like to get some feedback on this, however. Are there any performance implications. Is this bad design? Is this what others are doing? Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by blackdot
I could also just do what I was doing in C++ and store a list of OutputListeners.

Which is exactly what a .NET event does for you.

Share this post


Link to post
Share on other sites
Arild:

That is how I have it implemented in C# at the moment. I just wanted to know if this was a good way of doing it.

It is less clean than the C++ approach since I could create channels on the fly without having to change the object definitions; I would just create a Listener that listens on channel 16 and in my program, I could just dispatch to channel 16. In the new approach, since they are events, I will have to create a new event for each channel. But then, I haven't been working on this more than a day, so I haven't looked at it with an eye for reusability.

smr:

If I used non-event delegates, then I would have to store a list of those delegates and iterate through and execute them, correct?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I don't realy understand what you want to do.

Do you want something like:

OutputManager.AddListener( channel_id, some_function );

OutputManager.Write( channel_id, message );

?

But then I don't understand what you mean with non-event delegates... event delegates behave almost equal to non-event delegates. In fact I only know of two.
1. You can't use non-event delegates in interfaces
2. When used on a property you can only add and remove delegates (what you can with simple delegates, too) but you can't use the = operator to set the value.

Share this post


Link to post
Share on other sites
Quote:
Original post by blackdot
smr:

If I used non-event delegates, then I would have to store a list of those delegates and iterate through and execute them, correct?


I think so. Why wouldn't you want to use event delegates? You can make them private or protected to prevent other objects from invoking them if you wish.

Share this post


Link to post
Share on other sites
No, normal delegates will multicast:

using System;
using System.Collections.Generic;
using System.Text;

public class foo {
public delegate void foodel();
public foodel bar;
}

public class echoer {
public readonly string s;
public void echo() {
Console.WriteLine(s);
}
public echoer(string ss) { s = ss; }
}
class Program {
static void Main(string[] args) {
foo f1 = new foo();
echoer e1 = new echoer("moo.");
echoer e2 = new echoer("bleat.");
f1.bar += e1.echo;
f1.bar += e2.echo;
f1.bar += e1.echo;
f1.bar();
}
}



produces the expected:

moo.
bleat.
moo.


Specifying event is just a quick trick to hide everything in the delegate from other classes but += and -=.

[I think]

Share this post


Link to post
Share on other sites
I'm in Visual Studio .NET 2003. The compiler complains on the lines where you add the handlers. I had to change the program to the following to make it work:


class Program
{
static void Main2(string[] args)
{
foo f1 = new foo();
echoer e1 = new echoer("moo.");
echoer e2 = new echoer("bleat.");
f1.bar += new foo.foodel(e1.echo);
f1.bar += new foo.foodel(e2.echo);
f1.bar += new foo.foodel(e1.echo);
f1.bar();
}
}



Thanks for the heads up. I mocked up a class to do this with delegates and it works just fine. As a design decision is this method OK?

Share this post


Link to post
Share on other sites
Ah yes, I should've prefixed, as I'm using 2k5.

As far as design goes, I've little opinion on the matter. I've been using C# for about a week :]

Personally, I've always used Output objects as sinks, not as dispatchers. C#/.NET makes this easier by providing a better generalized Stream object/readers/writers and the ability to use Synchronized [on some?] to make them threadsafe. Things like logging strategy objects might use events/delegates to dispatch to various sinks, but those aren't [imo] best used through a single manager.

Share this post


Link to post
Share on other sites
EDIT: I just saw someone gave a similar answer... [grin]. I'll leave mine in here as example.

Actually, you can still use your channel idea, and benefit from the C# delegates/events.

Why not make a Channel class, and have that one dispatch the events?


public void delegate TextOutputEventHandler(object sender, TextOutputEventArgs e);

public class Channel
{
private int channel;
public event TextOutputEventHandler TextOutput;

public Channel(int channel)
{
this.channel = channel;
}

public int Channel
{
get { return channel; }
}

public void OutputText(string text)
{
if (TextOutput != null)
TextOutput(this, new TextOutputEventArgs(text));
}
}

public class ChannelManager // Or whatever you want
{
// ... Lotsa code here

public void AddOutputHandler(int channel, TextOutputEventHandler handler)
{
channel = channels.GetByKey(channel); // Psuedocode
if (channel != null)
{
channel.TextOutput += handler; // Subscribe
}
}
}


This will allow you to use the best of both worlds.

Toolmaker

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!