Multicast delegate weird behavior in C#? - c#

I have this simple event :
public class ClassA
{
public event Func<string, int> Ev;
public int Do(string l)
{
return Ev(l);
}
}
And 2 Methods :
static int Display(string k)
{
return k.Length;
}
static int Display_2(string k)
{
return k.Length*10;
}
Im registering this event :
ClassA a = new ClassA();
a.Ev += Display;
a.Ev += Display_2;
Now , I'm executing :
Console.WriteLine(a.Do("aaa"));
the output :
What ???
he has in invocation list 2 methods ! it did run them , but why does it shows only the result from the last registration ?
Where does the result of "3" has gone ? ( the first invocation ) ? ( although both display+display_2 was executed... I didn't expect console.write to iterate through results . but also didn't expect him to decide which to show.)
edit :

There are three aspects at play here:
The implementation of the event
The behaviour of delegate combination
The behaviour of invoking a delegate whose invocation list has multiple entries
For point 1, you have a field-like event. Section 10.8.1 of the C# 4 spec gives an example, and states that:
Outside the declaration of the Button class, the Click member can be used only on the left-hand saide of the += and -= operators, as in
b.Click += new EventHandler(...);
which appends a delegate to the invocation list of the Click event
(emphasis mine). The spec also makes it clear that a field-like event creates a delegate field, which is used from within the class for invocation.
More generally (point 2), section 7.8.4 of the C# 4 spec talks about delegate combination via + and +=:
Delegate combination. Every delegate type implicitly provides the following predefined operator, where D is the delegate type:
D operator +(D x, D y)
The binary + operato performs delegate combination when both operands are of some delegate type D. [... skip bits where x or y are null ...] Otherwise, the result of the operation is a new delegate that, when invoked, invokes the first operand and then invokes the second operand.
(Again, emphasis mine.)
Finally, point 3 - event invocation and return values. Section 15.4 of the C# spec states:
If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.
More generally, it depends on the event implementation. If you use an event implementation which uses the "normal" delegate combination/removal steps, everything is guaranteed. If you start writing a custom implementation which does crazy things, that's a different matter.

As a general rule, it doesn't make sense for events to return a value.
If you want to get information from an event handler it makes more sense for the event handlers to mutate an input parameter, or just call another method of whatever object fired the event to communicate something else.
Normally this doesn't even come up because events logically are passing information to the event handlers, and don't have any need to get information from the event handlers. It's honestly a sign of code smell. An event shouldn't care if anyone has subscribed to it, who they might be, what they might be doing, or even if there are any subscribers. Relying on a return value from them then just creates overly tight coupling.

Invoking a multicast non-void delegate returns the value of the last handler that was executed.
You have very little control over who is first or last. It is a lousy system to use.
That is why most events and delegates return void.

The events are just iterated in the order they were attached. Because you are using a return value, the value you get is the last invoked.
This is not really a normal pattern for events though. You probably want something a bit more like:
public class MyEventArgs : EventArgs
{
public MyEventArgs()
{
Results = new List<int>();
}
public string InputString{get;set;}
public List<int> Results{get;set;}
}
public event EventHandler<MyEventArgs> Ev
public int Do(string l)
{
MyEventArgs e = new MyEventArgs();
e.InputString = l;
if(Ev != null) Ev(this, e);
return e.Results.Sum();
}
and then
static int Display(object sender, MyEventArgs e)
{
return e.Results.Add(k.Length);
}
static int Display_2(object sender, MyEventArgs e)
{
return e.Results.Add(k.Length*10);
}

Related

Need help understanding an event being assigned "delegate { }"

While looking at an UWP example app, I came across this code. What I don't understand and can't seem to find in google is line 40:
public event PropertyChangedEventHandler PropertyChanged = delegate { };
Says in the comments that it is a multicast event. What does assigning delegate { } do? Does it have anything to do with the comment saying the event is multicast?
What does assigning delegate { } do?
That is simply adding an anonymous function to the event, with an empty body. Since C#3, one would generally use a lambda expression instead:
public event PropertyChangedEventHandler PropertyChanged = (s, e) => { };
However, lambda expressions require each parameter to be elicited, whereas using delegate does not. So if you don't need to use the arguments, then delegate may be more concise.
Microsoft highlight this as the single remaining use case of the delegate syntax for defining an anonymous function:
When you use the delegate operator, you might omit the parameter list. If you do that, the created anonymous method can be converted to a delegate type with any list of parameters. That's the only functionality of anonymous methods that is not supported by lambda expressions. In all other cases, a lambda expression is a preferred way to write inline code.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/delegate-operator
Does it have anything to do with the comment saying the event is multicast?
No; multicast means that you can add more than one handling function to the event, and when the event is raised, each one is invoked.
For example:
class Example
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseEvent()
{
PropertyChanged?.Invoke(default, default);
}
}
var example = new Example();
// Use the += operator to add a new handler (rather than = which overwrites)
example += delegate { Console.Writeline("Handler 1"); };
example += delegate { Console.Writeline("Handler 2"); };
example.RaiseEvent();
// Output:
// Handler 1
// Handler 2
Follow up question: What is the purpose of assigning an anonymous function to the event?
If no handler has been added, invoking the event can cause a NullReferenceException, so assigning an empty handler could remove the necessity to handle null.
So the event can be raised like this:
PropertyChanged.Invoke(default, default);
Or this:
PropertyChanged(default, default);
Rather than this:
PropertyChanged?.Invoke(default, default);
It's just an empty delegate, but the compiler will derive delegates from MulticastDelegate. So all delegates in C# are multicast.
Action d = delegate { };
// True
Console.WriteLine(d.GetType().BaseType == typeof(MulticastDelegate));

Subscribing to events using anonymous methods

I am having problems understanding how the below works (questions below code):
private delegate void MyDelegate(int i);
private event MyDelegate myEvent;
public void EventTests() {
//Option One
myEvent += One;
//Option Two
myEvent += delegate{ Two(true); };
//Option Three
myEvent += () => { Two(true); };
}
private void One(int i) { }
private void Two(bool j) { }
Questions:
I can understand why Option One works, as the event myEvent expects a delegate with an int parameter to be attached to it. Why does Option Two work though? it is attaching an anonymous method with incorrect signature to the event, no?
So if Option Two works, why does option Three not work? It seems that the signature needs to be (int i) => { Two(true); }; as opposed to () as written above. But Option Two worked without the right signature, so why does this anonymous method cause an error?
Thanks a lot.
Option two works because the compiler automatically figures out what the function signature is when the parameter list is omitted. Once you add the () to the delegate keyword, you've defined a specific parameter list of none and the compiler throws a fit.
Option three is a lambda expression with an incorrect parameter list defined.
Microsoft's C# Programming Guide states:
There is one case in which an anonymous method provides functionality not found in lambda expressions. Anonymous methods enable you to omit the parameter list. This means that an anonymous method can be converted to delegates with a variety of signatures. This is not possible with lambda expressions.

How do I change the name of an existing event handler?

In Windows Forms, if you change the method name (for example, button1_Click) to something else, it doesn't work any more.
I find this strange because in a console application, as far as I remember, you could name the methods as you wished. I'm trying to understanding what's happening.
How can I change the name of these methods (such as button1_Click)?
This questions is about the case where renaming a method causes the forms designer to stop working. Although I have covered (all that I can think of) how events works in general.
What happened?
What you experience is an artifact of the forms designer.
Sure, you can have any method name you want, the matter is the forms designer is binding those methods to events behind the scenes, if you change the method name after the forms designer has linked it to the event it will no longer work (it can't find the method).
Giving proper names to your event handlers
In Visual Studio, look at the properties of the object you want to bind an event to, and then select events (on the top of the panel):
There you will see a list the available events and you will be able to bind an existing method or type the name for a new one:
If I have already screwed, how do I fix it?
If your designer is not appearing because of this you will have to edit the code file that is generated by the designer. The file generated by the designer has the name of the form followed by .Designer.cs (for example: Form1.Designer.cs), you can find it with your solution explorer:
Note: You may have to expand the sub-tree created on your form to reveal the file.
There you will find a line that looks something like this:
this.button1.Click += new System.EventHandler(this.button1_Click);
And Visual Studio will tell you that button1_Click is not defined. You can edit there the name of the method to the new name, or remove the line to have the designer work again, and bind a new method.
Renaming an existing method without the hassle
You can summon the Rename dialog. This can be done by several ways:
From the Menus: Edit -> Refactor -> Rename
By contextual Menu on the name of the Method: Refactor -> Rename
Put the cursor on the Method name and type Alt + Shift + F10 and then select Rename
Put the cursor on the Method name and press F2
Note: You can customise your Visual Studio, the above menus and keyboard shortcuts may be changed.
The Rename dialog looks like this:
There you can type a new name for the method, and by doing so any reference or call to that method withing the loaded projects will be changed too. That includes the code generated by the Forms Designer.
Binding an event handler by hand
All that the forms designer does is present a UI that facilitates editing the form and write code on your behalf. Don't let it fool you into thinking that you can't write code yourself.
In fact, you can create your own methods and even bind them to the events of your Form. I have been saying "bind" because it is easier to understand at this level, although the accepted lingo is subscribe. So what we are going to do, is create a button and subscribe to its Click event.
First let's take a look at the class of your form, it looks something like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
Notice it says partial, that means that there could be more code for this class in another file, in fact that is the file Form1.Designer.cs where the forms designer has been adding code.
Second notice it calls a method InitializeComponent inside the constructor of the form. This method has been created by the forms designer and it takes responsibility of initializing all the controls and components you have added using the forms designer (hence the name of the method).
Now, let's say we want to add a button without the forms designer we can do it like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Button myButton;
public Form1()
{
InitializeComponent();
// Create a new Button
myButton = new Button();
// Set the properties of the Button
myButton.Location = new System.Drawing.Point(50, 12);
myButton.Size = new System.Drawing.Size(100, 23);
myButton.Text = "My Button";
// Add the Button to the form
this.Controls.Add(myButton);
}
}
}
We have created a private field named myButton of type Button that will hold the new button. Then inside the constructor we add some new lines to create a new Button and assign it to myButton and give it position (Location), Size and Text. And finally we have added the newly created button to the Controls of the form.
Now we want to add an event handler for the Click event on this new button. Remember that this button is not in the forms designer, we we are going to have to do it "by hand".
In order to do so, add the new method (you can named whatever you want):
private void WhenClick(object sender, System.EventArgs e)
{
/* Code */
}
And then add it as an event handler for the Click event of the button (inside the constructor):
// Add an event handler
myButton.Click += new System.EventHandler(WhenClick);
Notice we are not calling WhenClick. instead we are making a reference to it.
Then we are creating a new Delegate of type System.EventHandler that will wrap the reference to the method WhenClick. I suggest to learn about Using Delegates.
I repeat: we are not calling WhenClick. If we were to call WhenClick we would do something like this: WhenClick(param1, param2). Please note that this is not what we are doing here, we haven't added parenthesis (/*...*/) after the method name, so we are not doing a method call.
You can also use some syntactic sugar to make all this easier:
public Form1()
{
InitializeComponent();
// Create a new Button and set its properties
myButton = new Button()
{
Location = new System.Drawing.Point(50, 12),
Size = new System.Drawing.Size(100, 23),
Text = "My Button"
};
// Add the Button to the form
this.Controls.Add(myButton);
// Add an event handler (the compiler infers the delegate type)
myButton.Click += WhenClick;
}
You can even make the event handler an anonymous method:
// Add an event handler (the compiler infers the delegate type)
myButton.Click += (sender, e) =>
{
/* code */
};
What you see here is a C# Lambda expression (more info at MSDN Lambda expressions). Get used to these syntax, because you will see them more and more often.
Understanding events
You have already seen code like this:
button1.Click += button1_Click;
As I told you we are passing a delegate object that has a reference to button1_Click. But that's not all that happens here... we are also giving it to Click.
Let's recapitulate and see how delegates behave. You can think about a delegate like an object that holds a method, or a pointer to a function if you prefer.
To understand this, I'll present some examples you can run as console applications. The first one shows that you can change the method that a delegate points to during runtime:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
myfunc = Add2;
Console.WriteLine(myfunc(7)); // This prints 9
myfunc = MultBy2;
Console.WriteLine(myfunc(7)); // This prints 14
}
static int Add2(int x)
{
// This method adds 2 to its input
return x + 2;
}
static int MultBy2(int x)
{
// This method multiplies its input by 2
return x * 2;
}
Notice myfunc is typed as Func<int, int> this is a generic delegate type that takes an int and returns an int.
Also notice that when I say myfunc = Add2;, it is not calling Add2 (there are no parenthesis there), it is passing a reference of the method itself. the same is true for myfunc = MultBy2;: it is not calling MultBy2, we are passing it.
Using anonymous methods via lambda expressions you can write equivalent code is less lines:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
// This anonymous method adds 2 to its input
myfunc = x => x + 2;
Console.WriteLine(myfunc(7)); // This prints 9
// This anonymous method multiplies its input by 2
myfunc = x => x * 2;
Console.WriteLine(myfunc(7)); // This prints 14
}
Notice that we have two anonymous methods here: x => x + 2 and x => x * 2. The first one (x => x + 2) is equivalent to the method Add2 we had before, and the second one (x => x * 2) is equivalent to the method MultBy2 we had before.
In this example I want you to see that the same delegate can point to different methods along the time. This is accomplished by having a variable that points to the methods!
For the second example, I'll present the "callback" pattern. That is a common pattern in which you pass a delegate as a "callback", that is: something that will be called "back to you" from the code you are calling:
// Console Application Example #2 ;)
static void Main()
{
Func<int, bool> filter = IsPair;
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, filter);
}
static bool IsPair(int x)
{
// True for pair numbers
return x % 2 == 0;
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
Outputs:
2
4
8
In this code we are having a variable filter that points to the method IsPair. I'll repeat this again and and again: in the line Func<int, bool> filter = IsPair; we are not calling the method IsPair, instead we are taking a reference to it.
Of course, it is possible to do the same without declaring the filter variable, you can pass the method reference directly:
// Console Application Example #2 ;)
static void Main()
{
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, IsPair); //<---
}
static bool IsPair(int x)
{
// True for pair numbers
return x % 2 == 0;
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
I cannot stress this hard enough: When I say PrintFiltered(array, IsPair); it is not calling IsPair, it is passing it as a parameter to PrintFiltered. Here effectively you have a method (PrintFiltered) that can take a reference to another method (IsPair) as a reference.
Of course you can write the same code using an anonymous method that replaces IsPair:
// Console Application Example #2 ;)
static void Main()
{
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, x => x % 2 == 0);
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
Outputs:
2
4
8
In this example x => x % 2 == 0 is an anonymous method that is equivalent to the method IsPair we had before.
We have successfully filtered the array to only show the numbers that are pair. You can easily reuse the same code for a different filter. For example, the following line can be used to output only the items in the array that are less than 10:
PrintFiltered(array, x => x < 10);
Outputs:
1
2
3
4
7
8
9
With this example I want to show you that you can take advantage of the delegates to improve the reusability of your code, by having parts that change depending on the delegate you pass.
Now that - hopefully - we understand this, it is not hard to think that you could have a list of Delegate objects, and call them in succession:
// Console Application Example #3 ;)
static void Main()
{
// List<Action<int>> is a List that stores objects of Type Action<int>
// Action<int> is a Delegate that represents methods that
// takes an int but does not return (example: void func(int val){/*code*/})
var myDelegates = new List<Action<int>>();
// We add delegates to the list
myDelegates.Add(x => Console.WriteLine(x));
myDelegates.Add(x => Console.WriteLine(x + 5));
// And we call them in succesion
foreach (var item in myDelegates)
{
item(74);
}
}
Outputs:
74
79
You can see both anonymous methods (x => Console.WriteLine(x) and Console.WriteLine(x + 5)) has been called, one after the other... this happens inside the foreach loop.
Now, we can accomplish similar results with a multicast delegate:
// Console Application Example #3 ;)
static void Main()
{
// This is a delegate... we haven't give it a method to point to:
Action<int> myDelegates = null;
// We add methods to it
myDelegates += x => Console.WriteLine(x);
myDelegates += x => Console.WriteLine(x + 5);
// And we call them in succession
if (myDelegates != null) // Will be null if we don't add methods
{
myDelegates(74);
}
}
Outputs:
74
79
Again, both anonymous methods has been called. And this is exactly how events work. The default implementation of an event uses a multicast delegated wrapped inside. Custom implementation of an event may use a list or similar structure to hold the delegates.
Now, if the event is just a list of delegates... that means the event is keeping a reference to all the methods it wants to call. And it also means that you could remove delegates from the list (or add more than one).
If you want to unsubscribe or unbind from an event, you can do so like this:
this.button1.Click -= button1_Click;
For a delegate object to an anonymous method it is a little bit more complicated, because you will need to keep the delegate in a variable to able to pass it back for removal:
Action<int> myDelegates = null;
// Create the delegate
var myDelegate = x => Console.WriteLine(x);
// Add the delegate
myDelegates += myDelegate;
// ...
// Remove the delegate
myDelegates -= myDelegate;
Did you say custom implementation of an event?
Does that means you can create your own events? Yes, and yes. If you want to publish an event in one of your classes you can declare it just like any other member.
This is an example that uses a multicast delegate:
// Event declaration:
public event EventHandler MyEvent;
// Method to raise the event (aka event dispatcher):
priavet void Raise_MyEvent()
{
var myEvent = MyEvent;
if (myEvent != null)
{
var e = new EventArgs();
myEvent(this, e);
}
}
For a custom implementation take this example:
// List to hold the event handlers:
List<EventHandler> myEventHandlers = new List<EventHandler>();
// Event declaration:
event EventHandler MyEvent
{
add
{
lock (myEventHandlers)
{
myEventHandlers.Add(value);
}
}
remove
{
lock (myEventHandlers)
{
myEventHandlers.Remove(value);
}
}
}
// Method to raise the event (aka event dispatcher):
private void Raise_MyEvent()
{
var e = new EventArgs();
foreach (var item in myEventHandlers)
{
item(this, e);
}
}
Hopefully this not hard to read, now that you know how events work. The only details should be lock, it is there because List is not thread-safe. You could also use a thread-safe data structure or a different locking mechanism, I kept this one for simplicity.
Even if you don't write your own events, there are a few things to learn from here:
Event handlers execute consecutively (by default), so it is good idea that event handlers execute fast (maybe defer to asynchronous operations for the hard work) to prevent "clogging" the event dispatcher.
The event dispatcher usually don't handle exceptions (it can be done), so it is good idea to avoid throwing excepting in event handlers.
The "publisher" of the event is keeping a list of the event handlers, it is a good idea to unsubscribe when you don't need need the event handler anymore.
Notes:
While looking for example I found the series of articles "Delegates in C# - Attempt to Look Inside" by Ed Guzman (Part 1, Part 2, Part 3 and Part 4) very easy to read - although a bit outdated - you should check them out. You may want to read the Evolution of Anonymous Functions in C# for a grasp of what's missing.
Some commonly used Delegate Types built-in in .NET include:
Generic
Action<*> (that is: Action<T>, Action<T1, T2> ...)
Func<*, TResult> (that is: Func<T, TResult>, Func<T1, T2, TResult> ...)
EventHandler<TEventArgs>
Comparison<T>
Converter<TInput, TOutput>
Non Generic
Action
Predicate
EventHandler
ThreadStart
ParametrizedThreadStart
You may be interested in LINQ.
Threading and thread-safety it a even broader topic than delegates and events, don't rush to understand it all.
If you want play along with Lambda Expression and C# in general, I suggest to get a copy of LINQPad. This make reduce the hassle of creating new project to test things.
You can of course change the name of your event. It just sounds like you don't know about the designer file :)
The designer file is just the result of your UI design, and if you don't update the name of your event in the UI it does not compile :)

I don't understand the difference between pure delegate and event fields

Delegate : I understand. But when I move to event, many things I don't understand so much. I read book, MSDN and some simple examples on Network, they both have same structures. For example, here is the link : Event Example
I take the first example, that the author said it's the most easiest example about C# Event.
Here is his code :
public class Metronome
{
public event TickHandler Tick;
public EventArgs e = null;
public delegate void TickHandler(Metronome m, EventArgs e);
public void Start()
{
while (true)
{
System.Threading.Thread.Sleep(3000);
if (Tick != null)
{
Tick(this, e);
}
}
}
}
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}
private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}
class Test
{
static void Main()
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m);
m.Start();
}
}
You can notice line: public event TickHandler Tick. When I change to public TickHandler Tick, program still run the same. But new line I understand because it's just a pure delegate.
So, my question is : what is the real purpose of event keyword in line : public event TickHandler Tick. This is very important, because all examples always use like this, but I cannot explain why.
Thanks :)
Delegates and events are related concepts, but they are not the same thing. The term "delegate" tends to have two meanings (often glossed over):
A delegate type which is similar to a single method interface. (There are significant differences, but that's a reasonable starting point.)
An instance of that type, often created via a method group, such that when the delegate is "invoked", the method is called.
An event is neither of those. It's a kind of member in a type - a pair of add/remove methods, taking a delegate to subscribe to or unsubscribe from the event. The add and remove methods are used when you use foo.SomeEvent += handler; or foo.SomeEvent -= handler;.
This is very similar to how a property is really a pair of get/set methods (or possibly just one of the two).
When you declare a field-like event like this:
public event TickHandler Tick;
the compiler adds members to your class which are somewhat like this:
private TickHandler tick;
public event TickHandler
{
add { tick += value; }
remove { tick -= value; }
}
It's a bit more complicated than that, but that's the basic idea - it's a simple implementation of the event, just like an automatically implemented property. From inside the class, you can access the backing field, whereas outside the class you'll always end up just using the event.
Personally I think it's a pity that the declaration of a field-like event looks so much like a field of a delegate type - it leads to some of the misleading (IMO) statements found in some of the answers, as if the event keyword "modifies" a field declaration - when actually it means you're declaring something entirely different. I think it would have been clearer if field-like events looked more like automatically-implemented properties, e.g.
// Not real C#, but I wish it were...
public event TickHandler Tick { add; remove; }
I have a whole article going into rather more detail, which you may find useful.
The event keyword basically restricts the operation on your delegate.
You can no longer assign it manually using the = operator.
You can only add (using +=) or remove (using -=) delegates from your event, one by one. This is done in order to prevent some subscriber to "overwrite" other subscriptions.
Consequently, you cannot do: m.Tick = new Metronome.TickHandler(HeardIt)
"event" is a modifier. What's the benefit?
you can use events in interfaces
only the class declaring it can invoke an event
events expose an add and remove accessor that you can override and do custom stuff
events limit you to a specific signature of the assigned method SomeMethod(object source, EventArgs args) which provide you with additional information about the event.
You're correct - the addition of the event keyword seems to be almost redundant. However, there's a key difference between fields that are events and fields that are typed to a pure delegate. Using the event keyword means that objects external to the containing object can subscribe to the delegate, but they cannot invoke it. When you drop the event keyword, external objects can subscribe AND invoke the delegate (visibility permitting.)
When you add a listener to your program you add the event, not the delegate
see your code m.Tick +=
you see that part right there is you are asking for the property (type event) and you are adding to it a listener with the +=. Now you can only add to that Tick property a TickHandler type and if you override it you have to make your own that is the same format as TickHandler.
much like when you add to a string, or int.
string stringTest = string.Empty;
stringTest += "this works";
stringTest += 4; //this doesn't though
int intTest = 0;
intTest += 1; //works because the type is the same
intTest += "This doesn't work";
Metronome m = new Metronome();
Metronome.TickHandler myTicker = new Metronome.TickHandler(function);
m.Tick += myTicker; //works because it is the right type
m.Tick += 4; //doesn't work... wrong type
m.Tick += "This doesnt work either"; //string type is not TickHandler type
does that clear it up some?
As far as i'm informed an event is basically a multicast delegate, but with different access rules for the basic operations, that can be performed on delegates and events from within or outside the class they are defined in.
The operations are:
assign using the = operator
add/remove using the += and -= operator
invoke using the () operator
Operation | delegate | event
------------------+------------+--------
Inside class += / -= | valid | valid
------------------+------------+--------
Inside class = | valid | valid
------------------+------------+--------
Inside class () | valid | valid
------------------+------------+--------
Outside class += / -= | valid | valid
------------------+------------+--------
Outside class = | valid | not valid
------------------+------------+--------
Outside class () | valid | not valid
This gives you encapsulation which is always good OOP style. :-)
I think the main difference between using delegate and event is that the event can be only raised by the Server (means the author of the class)
If you remove the event keyword now you can raise the m.Tick(sender,e) in the Listener otherwise not.
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}
private void RaisTick(object sender, EventArgs e)
{
m.Tick(sender,e);
}
private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}

C# Delegates and Events logic and syntax issues

As my code suggests, I'm trying to create a delegate which will point to the StringBuff method BuffString, which creates a StringBuilder that is going to have a fair amount of settings, etc.
My problem is that, for some reason, no matter what it is I try I can't pass the reference to the StringBuff class I made within my Sprite class to the delegate's constructor without receiving an error. Ontop of that, I feel like creating an event may be useful to help initiate the delegate.
The main problem is that I'm just now barely grasping these two concepts, as well as how to use them as replacements for function pointers which are allowed in other programming languages.
If anyone has any idea on what it is I need to do to make this work, I would definitely appreciate it.
Here's the code:
public class StringBuff
{
private static StringBuilder stringBuffer = new StringBuilder();
public static StringBuilder BuffString(string _string) //--may possibly have to use IntPtr to reference stringBuffer here.
//This is the equivalent to the "strbuff_new" C++ method variant, designed to update the stringBuffer.
{
int iCounter = 0;
stringBuffer.Append(_string + " ");
iCounter += _string.Length + 1;
if (iCounter == stringBuffer.Capacity - 1)
{
stringBuffer.Capacity += stringBuffer.Capacity;
}
return stringBuffer;
}
}
public delegate void UpdateStringBuffer(StringBuff sender);
public class Sprite : SpriteInterface.ISprite
{
private StringBuff stringBuff = new StringBuff();
public event UpdateStringBuffer stringBuffEvent
{
add
{
Console.WriteLine("Adding");
stringBuffEvent += value;
}
remove
{
Console.WriteLine("Removing...");
stringBuffEvent -= value;
}
}
static void Main()
{
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
}
}
I believe you are in need for some reading. Refer to the following:
Events Tutorial
Introduction to Delegates and Events
Events and Delegates simplified
You are misunderstanding the use of events and delegate.
When you want to add an Event Handler to an event, you pass a delegate of the same type as the event (which you did correctly)
But when you create a delegate, what you should pass in the constructor (most of the time) is a Method Name and not some variable, since a delegate is a kind of pointer to a (list of) functions.
I reccomend you to read more about delegates as Akram Shahda suggested but just for now i'll tell you that the method that you should pass as parameter to the delegate constructor should have the same signature - means return the same value and accept the same parameters. so for example you could have:
// This method have the same signature as UpdateStringBufferDelegate
public void SomeMethod (StringBuff buff)
{
// Doing somthing here
}
And then you can do in your main:
// Passing method's name and not a variable!!
new Sprite().stringBuffEvent += new UpdateStringBuffer(SomeMethod);
The Actuall parameters that will be passed to the function itself (some StringBuff) only determined at the time of the invokation of the event.
You should read more about that.
Good Luck!
you are doing it wrong,
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
Above code is invalid due to following reasons.
1. stringBuff that your UpdateStringBuffer is taking is an instance of StringBuff within Sprite.
2. You are accessing stringBuff from the static Main method which does not have any idea about stringBuff where it is located.
1- The delegate's constructor can only have a parameter Method. Ex
public delegate void UpdateStringBuffer(StringBuff sender);
2- You can declare ur event and add a method to define ur method in ur Splite class. Ex:
public event UpdateStringBuffer stringBuffEvent;
public ProcessUpdateStringBuffer(UpdateStringBuffer yourMethod)
{
stringBuffEvent += yourMethod
}
3- and from ur main u can define ur method to the event and invoke it like this:
Sprite sprite = new Sprite();
sprite.ProcessUpdateStringBuffer(UpdateStringBuffer(urMethod));
sprite.stringBuffEvent(ur parameters);

Categories