Difference between private EventHandler and private event EventHandler? - c#

Basically what the title says.
Whats the difference between those two (I am currently using the first one)
private EventHandler _progressEvent;
and
private event EventHandler _progressEvent;
I have a method
void Download(string url, EventHandler progressEvent) {
doDownload(url)
this._progressEvent = progressEvent;
}
The doDownload method would call the
_progressEvent(this, new EventArgs());
It works fine, so far. But I feel I am doing something horribly wrong.

The first defines a delegate, the second defines an event. The two are related, but they're typically used very differently.
In general, if you're using EventHandler or EventHandler<T>, this would suggest that you're using an event. The caller (for handling progress) would typically subscribe to the event (not pass in a delegate), and you'd raise the event if you have subscribers.
If you want to use a more functional approach, and pass in a delegate, I would choose a more appropriate delegate to use. In this case, you're not really providing any information in the EventArgs, so perhaps just using System.Action would be more appropriate.
That being said, an event approach appears more appropriate here, from the little code shown. For details on using events, see Events in the C# Programming Guide.
Your code, using events, would likely look something like:
// This might make more sense as a delegate with progress information - ie: percent done?
public event EventHandler ProgressChanged;
public void Download(string url)
{
// ... No delegate here...
When you call your progress, you'd write:
var handler = this.ProgressChanged;
if (handler != null)
handler(this, EventArgs.Empty);
The user of this would write this as:
yourClass.ProgressChanged += myHandler;
yourClass.Download(url);

For private, there is no difference between the two, but for public you would want to use event.
The event keyword is an access modifier like private internal and protected.
It is used for restricting access to multicast delegates. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/event
Going from most visible to least visible we have
public EventHandler _progressEvent;
//can be assigned to from outside the class (using = and multicast using +=)
//can be invoked from outside the class
public event EventHandler _progressEvent;
//can be bound to from outside the class (using +=), but can't be assigned (using =)
//can only be invoked from inside the class
private EventHandler _progressEvent;
//can be bound from inside the class (using = or +=)
//can be invoked inside the class
private event EventHandler _progressEvent;
//Same as private. given event restricts the use of the delegate from outside
// the class - i don't see how private is different to private event

Related

Simplest way to handle creating events in a class

While playing around in VS 2015, i was creating a property and mistyped prior to hitting tab and it gave me what appears to be a very clean simple method for creating an event. I am unsure how to use this to accept additional parameters to pass it data (as I usually want to pass data when raising an event with information about what is in progress, or what was done)
The code it gave is as follows :
public event EventHandler<EventArgs> MyEvent;
protected virtual void OnMyEvent(EventArgs e)
{
EventHandler<EventArgs> handler = MyEvent;
if (handler != null)
handler(this, e);
}
At first glance it is similar to most examples however this method does not appear to require a delegate to operate. Compare with the following example from How to call an event manually in C#?
public delegate void MyEventHandler(object sender, MyEventArgs e)
public event MyEventHandler MyEvent;
public void RaisesMyEvent()
{
if(MyEvent != null) //required in C# to ensure a handler is attached
MyEvent(this, new MyEventArgs(/*any info you want handlers to have*/));
}
What I would like to know, in light of having more elegant (clean) code, is the method that microsoft provided (first method in this question) better (it seems cleaner), and if so, how could I adjust it slightly to accept a string in addition to standard event args and/or extend the eventargs to pass information ?
To pass custom arguments on an EventHandler, you would create your own class derived from EventArgs and change the declaration like so:
public event EventHandler<MyCustomEventArgs> MyEvent;
Alternatively, if you don't like having object sender in your handlers, you can do:
public event Action<MyCustomEventArgs> MyEvent;
or even
public event Action<string> MyEvent;
As far as the invocation, Microsoft's is better. The reason is that the null check you wrote isn't thread-safe. Storing off the handler before doing the null check ensures that you don't invoke a null method.
Alternatively, use C# 6 invocations and take advantage of the null conditional operator:
MyEvent?.Invoke(whateverArgs);
The code that Visual Studio auto-generated for you is actually better for one small condition:
public void RaisesMyEvent()
{
if(MyEvent != null) //required in C# to ensure a handler is attached
// Now if someone in another thread sets MyEvent to null the next line will still execute
MyEvent(this, new MyEventArgs(/*any info you want handlers to have*/));
// And throw a NullReferenceException
}
This code has a race condition. It's fairly rare to hit it, but it is possible. The Visual Studio boilerplate code avoids this race condition by making a local copy of the event handler before calling it.
As for how to pass more parameters to the event handler:
There are multiple ways, but the 'standard' way is to create an class that extends EventArgs. For instance, PaintEventArgs extends EventArgs and adds a Graphics and Rectangle properties for the OnPaint handler to use.
I'd follow that basic pattern by creating a MyEventArgs class based off EventArgs, and adding the properties your method will need to use.
Just replace EventArgs with your own class:
class MyEventArgs : EventArgs
{
public string Text { get; private set; }
public MyEventArgs(string text)
{
Text = text;
}
}
The EventHandler<T> generic delegate type will accept EventArgs or any subclass of EventArgs.
Then when you call OnMyEvent(), just pass an instance of your class with the data you want to deliver with the event.
I agree with the other notes regarding thread-safe invocation. This isn't always required, but it's simple enough to implement and the IDE-provided version is safe while yours is not.

Action<T> is different event Action<T>?

public class TestA
{
public event Action<int> updateEvent;
...
if(updateEvent != null)
{
Actin<int> tempEvent = updateEvent;
updateEvent(1);
}
}
public class TestB
{
public Action<int> updateEvent;
...
if(updateEvent != null)
{
Actin<int> tempEvent = updateEvent;
updateEvent(1);
}
}
however event Action<T> is eventQueue au
use same and resutl same. What is more good? (i like TestB. Because simple using.)
The event modifier is useful to prevent an assignment. What does it mean? If that's a callback with many handlers attached you may want to prevent that someone simply write:
myObject.UpdateEvent = null or something like that. With event they can't do that. Take a look at Learning C# 3.0: Master the fundamentals of C# 3.0.
The code you use to call the event isn't bad but not so useful, if you assign the delegate to temporary variable you may want to be somehow thread-safe (someone could unhook after your null check) so you should do it before the check:
Action<int> tempEvent = updateEvent;
if (tempEvent != null)
tempEvent(1);
A little side note: if you use events you may want to follow .NET Framework patterns and guidelines, take a look at MSDN
To the compiler, the difference is that the event cannot be invoked except by the declaring class (like a private member). You can use either in the same way.
To design, events should represent their namesake, i.e. events. Think of a Delegate as just the type or signature of methods. You would declare a class to have an event (of type Action), and you would add (subscribe) to that event other Actions (or methods that can be cast to an Action).
Furthermore, it is common practice to create events of a type that inherits from EventHandler<T>
An event is just a delegate with some access wrappers.
The problem with your TestB is that because the updateEvent delegate is public, ANYONE can fire the delegate, not just the class owning it.
Defining it as an Event as in your TestA, client code can only subscribe or unsubscribe to the event, they cannot fire it.
ps. You do not need your tempEvent delegates.

How do I extract an event handler to another file and still have access to sender and args?

I attached an event handler to Entity Framework's SavingChanges event. Now, I found out I need to attach the same event handler somewhere else in the solution. Both situations (maybe even more if we dig deeper) require the same code so it makes sense to extract to a method and call the same method from multiple event handlers.
The method body includes references to the sender object and eventargs. How do I pass these parameters to the method, even when it's in its own class ?
The sender and event arguments should be part of your method signature and will be passed to the method you are writing when the event is fired. So the variables are defined as parameters to your event handler, and the values for those will be sent by the event trigger.
// I don't know what the proper signature is for a SavingChanges event handler
public class EventHandlers
{
public static void SavingChangesHandler(object sender, EventArgs args)
{
// do something with sender and args here
}
}
// in your other code
SomeObject.SavingChanges += EventHandlers.SavingChangesHandler;

c# Using a reference to an event member

Anybody know why this is not possible?
If the event is just a MulticastDelegate instance you should be able to reference it in the code. the compiler says EventA can only be on left side of -= or +=.
public delegate void MyDelegate();
public event MyDelegate EventA;
public void addHandlerToEvent(MulticastDelegate md,Delegate d){
md+=d;
}
///
addHandlerToEvent(EventA,new MyDelegate(delegate(){}));
An event is not a multicast delegate, just like a property is not a field.
C#'s event syntax wraps multicast delegates to make life easier by providing syntactic sugar for adding and removing handler delegates. Your event definition would be compiled to the following:
private MyDelegate _EventA;
public event MyDelegate EventA
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_EventA = (MyDelegate)Delegate.Combine(_EventA, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_EventA = (MyDelegate)Delegate.Remove(_EventA, value);
}
}
The add and remove methods within the expanded event definition are then called when you use operator += and operator -= on the event.
This is done in order to hide the internals of the multicast delegate, but expose a simple way to implement publishing/subscribing to events. Being able to get the underlying delegate (outside of the class where it's defined) would break that intentional encapsulation.
An event is a member which binds a pair of add/remove methods(*), each of which accepts a delegate corresponding to the event signature. By default, the C# compiler will for each event auto-define a MultiCast delegate field along with add and remove members which will take the passed-in delegate and add or remove them to/from that MulticastDelegate field. The statement myEvent += someMethod;, when performed outside the class defining the event, is the required syntactic shorthand for, essentially myEvent.AddHandler(someMethod), and myEvent -= someMethod; for myEvent.RemoveHandler(someMethod), except that there is no way in C# to call the add/remove methods except using the += and -= notation.
Things are a little tricky when using the += and -= notation within the class which defines an event, since the field defined by the auto-generated event code has the same name as the event, and the behavior of myEvent += someMethod; will vary with different versions of C#.
(*) Technically a trio, since an event also includes a 'raise' method, but in practice that method is essentially never used.
Events are backed by multicast delegates, yes, but their purpose is to provide an implementation of the observer pattern, where observers (delegates in this case) may only be registered (+=) or unregistered (-=). If normal access to the backing delegate were possible outside the class itself, then it would be possible for client code to interfere with an unrelated delegate that was registered elsewhere, which could mess things up. It's also somewhat beside the point of the observer pattern to look at which other things are observing the event in question.
If you need to perform this kind of manipulation of the backing delegate, it must be done within the class (where it's treated as a regular delegate rather than an event).
You can also implement the backing delegate explicitly and provide an accessor to register/unregister with it:
private EventHandler SomeEvent;
public event EventHandler
{
add
{
SomeEvent += value;
}
remove
{
SomeEvent -= value;
}
}
This way you can provide direct access to the delegate if you need to. It's still best to provide public access to it for the purposes of subscribing/unsubscribing as an event though (rather than a raw delegate), otherwise you can run into thread-safety problems with data races on the delegates.

Raising events in C# from classes

Basically I am attempting to write a generic interprocess communication implementation between C# and the Android platform (using Java).
Creating the socket stack is simple enough but what I am wondering is what would be a good pattern to passing in delegates into my TcpServer class and raising the required events.
The idea so far is.
while (connected) {
//Compile all the required data and so forth
switch (currentState)
{
case CurrentServerState.EventReceived:
//Raise my event...
break;
case CurrentServerState.ObjectReceived:
break;
}
}
So would the correct implementation simply expose an array of delegates and use reflection to match event names or something along those lines? What are my options? Also how do I make sure that any raised events are raised in the UI thread given that this is all occurring from a thread created for the server?
If you don't need to pass any custom arguments to the event handler you can use the default EventHandler delegate which uses the base EventArgs.
Declare the events you want to make available like this:
public event EventHandler EventReceived;
public event EventHandler ObjectReceived;
Declare a protected method for each event to handle raising the event for you. This is really just a convenience to keep from repeating this each time you need it. You could do this inline.
Your events will be null if there are no attached event handlers. The method handles checking for this before firing the event.
protected void RaiseEventReceived(EventArgs e)
{
if (EventReceived != null)
EventReceived(this, e);
}
Then call the method when you want to raise the event. The method will handle checking to see if anyone is listening for the event.
public void SomeOtherMethod()
{
while (IsConnected)
{
switch (CurrentState)
{
case CurrentServerState.EventReceived:
RaiseEventReceived(EventArgs.Empty);
break;
case CurrentServerState.ObjectReceived:
RaiseObjectReceived(EventArgs.Empty);
break;
}
}
}
You can declare your own class to pass custom arguments to the event handlers by deriving from EventArgs such as the following. By convention your class should be named *something*EventArgs.
public class EventReceivedEventArgs : EventArgs
{
// Declare properties to hold additional event info here
}
Then you would need to declare a custom delegate that takes your new event args parameter:
public delegate void EventReceivedEventHandler(object sender, EventReceivedEventArgs e);
Update your event declarations to use your new delegate type instead of EventHandler:
public event EventReceivedEventHandler EventReceived;
And finally, when raising the event you of course would want to create a new instance of your custom event arguments class and intitialize your custom properties.
Clients can attach multiple handlers to your events using the normal syntax and they will always be called on the correct thread.

Categories