I was looking at this question and while I think I mostly understand event accessors two other aspects of this confused me.
First:
private event Action<int> ActivityChanged = delegate {};
Was this event assigned a value with variable-initializers, my understanding was that only += and -= operators were permmited on events? What does the anonymous method do here?
Second:
event Action<int> IActivityFacade.ActivityChanged
{
add
{
ActivityChanged += value;
value(GetSelectedActivity());
}
remove { ActivityChanged -= value; }
}
Was the first line a forward declaration and the second a definition? I come from a C++/C background and that is what this appeared to me but for all I know it could mean something else entirely. Are forward declarations even allowed in C#
first line is private member and actual 'event' with dummy initializer. event have operators += and -= for subscribe and unsubscribe, without dummy it throws null reference
second is a publicly available accessor for subscribers with same += and -=
with member event you can fire them as follow this.ActivityChanged() some example
IActivityFacade.ActivityChanged this mean class implements interface and we explicitly define it as event accessor about interface events and explicit enterface
Related
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));
TreeList1.FocusedNodeChanged += treeList1_FocusedNodeChanged;
Specifically what does the += do?
It is used to assign event handlers to events.
From MSDN:
The += operator is also used to specify a method that will be called in response to an event; such methods are called event handlers. The use of the += operator in this context is referred to as subscribing to an event. For more information, see How to: Subscribe to and Unsubscribe from Events (C# Programming Guide). and Delegates (C# Programming Guide).
In your case, it assigns the treeList1_FocusedNodeChanged handler to the FocusedNodeChanged event of TreeList1.
Additional Info:
The function of the += operator depends on the context. While in your case it is used to subscribe to an event, in other cases, it may be used for addition assignment.
Say for example, this code:
int x = 5;
x += 6; // This basically translates to x = x + 5, thus assigning x a value of 11.
Also, you can use lambda expressions instead of a separate method while subscribing to events:
TreeList1.FocusedNodeChanged += (s, e) => { // ... // };
The code in place of // ... // would be whatever there was in the separate event handler.
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);
}
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");
}
}
I am writing integration tests that involve FileSystemWatcher objects. To make things easier, I want to unsubscribe everything from an event delegate without having to hunt down every subscription. I already saw related post, Is it necessary to unsubscribe from events?. This is somewhat a duplicate, but I am specifically asking why this doesn't work with a FileSystemWatcher object.
It would be nice to do something like the following:
private void MethodName()
{
var watcher = new FileSystemWatcher(#"C:\Temp");
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
watcher.Changed = null; // A simple solution that smells of C++.
// A very C#-ish solution:
foreach (FileSystemEventHandler eventDelegate in
watcher.Changed.GetInvocationList())
watcher.Changed -= eventDelegate;
}
No matter how the Changed event is referenced, the compiler reports:
The event 'System.IO.FileSystemWatcher.Changed' can only appear on the left hand side of += or -=
The above code works just fine, when working with an event in the same class:
public event FileSystemEventHandler MyFileSystemEvent;
private void MethodName()
{
MyFileSystemEvent += new FileSystemEventHandler(watcher_Changed);
MyFileSystemEvent = null; // This works.
// This works, too.
foreach (FileSystemEventHandler eventDelegate in
MyFileSystemEvent.GetInvocationList())
watcher.Changed -= eventDelegate;
}
So, what am I missing? It seems that I should be able to do the same with the FileSystemWatcher events.
When you declare event in your class, it is an equivalent (almost) of the following code:
private FileSystemEventHandler _eventBackingField;
public event FileSystemEventHandler MyFileSystemEvent
{
add
{
_eventBackingField =
(FileSystemEventHandler)Delegate.Combine(_eventBackingField, value);
}
remove
{
_eventBackingField =
(FileSystemEventHandler)Delegate.Remove(_eventBackingField, value);
}
}
Notice that there is no set or get accessor for event (like for properties) and you can't explicitly write them.
When you write MyFileSystemEvent = null in your class, it is actually doing _eventBackingField = null, but outside your class there is no way to directly set this variable, you have only event add & remove accessors.
This might be a confusing behavior, because inside your class you can reference an event handler delegate by event name, and can't do that outside the class.
Short answer is += and -= are public operators while = is a private operator to the class that's declaring the event.