delegate, event convention that I don't understand - c#

I looked at this example from the C# in nutshell book
(http://www.albahari.com/nutshell/ch04.aspx)
using System;
public class PriceChangedEventArgs : EventArgs
{
public readonly decimal LastPrice;
public readonly decimal NewPrice;
public PriceChangedEventArgs (decimal lastPrice, decimal newPrice)
{
LastPrice = lastPrice; NewPrice = newPrice;
}
}
public class Stock
{
string symbol;
decimal price;
public Stock (string symbol) {this.symbol = symbol;}
public event EventHandler<PriceChangedEventArgs> PriceChanged;
****protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
if (PriceChanged != null) PriceChanged (this, e);
}****
public decimal Price
{
get { return price; }
set
{
if (price == value) return;
OnPriceChanged (new PriceChangedEventArgs (price, value));
price = value;
}
}
}
class Test
{
static void Main()
{
Stock stock = new Stock ("THPW");
stock.Price = 27.10M;
// register with the PriceChanged event
stock.PriceChanged += stock_PriceChanged;
stock.Price = 31.59M;
}
static void stock_PriceChanged (object sender, PriceChangedEventArgs e)
{
if ((e.NewPrice - e.LastPrice) / e.LastPrice > 0.1M)
Console.WriteLine ("Alert, 10% stock price increase!");
}
}
What I don't understand, is why this convention is used...
****protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
if (PriceChanged != null) PriceChanged (this, e);
}****
Why do I need that method and why do I care to give it the "this" parameter?!? Cant I just attach the event from that class with the method PriceChanged in the test class straight away and skip that method?!?

You need the null check, since an event will be null until somebody subscribes to it. If you raise it directly and it's null, an exception will be thrown.
This method is used to raise the event, not to subscribe to it. You can subscribe to the event from another class easily:
yourObject.PriceChanged += someMethodWithTheAppropriateSignature;
However, when you want to have the event "fire", the class needs to raise the event.
The "this" parameter is providing the sender argument in the EventHandler<T>. By convention, delegates used for events have two parameters, the first is object sender, which should be the object that raised the event. The second is EventArgs or a subclass of EventArgs, which provides the information specific to that event. The method is used to properly check for null and raise the event with the appropriate information.
In this case, your event is declared as:
public event EventHandler<PriceChangedEventArgs> PriceChanged;
EventHandler<PriceChangedEventArgs> is a delegate which has a signature of:
public delegate void EventHandler<T>(object sender, T args) where T : EventArgs
This means that the event must be raised with two parameters - an object (the sender, or "this"), and an instance of PriceChangedEventArgs.
That being said, this convention is not actually the "best" way to raise the event. It would actually be better to use:
protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
var eventHandler = this.PriceChanged;
if (eventHandler != null)
eventHandler(this, e);
}
This protects you in multi-threaded scenarios, since it's possible that a single subscribe could actually unsubscribe in between your null check and the raise if you have multiple threads operating.

This is a convenience for invoking the event.
You do need to check that the event has subscribers, and it is typical to pass this as the sender of the event.
Because the same handler can be used for multiple events, passing an instance of the sender is the only way that you could reliable unsubscribe from the event once it has fired.
I think the preferred way to invoke is to assign to a variable first, lest PriceChanged become null after checking, but before invoking:
var handler = PriceChanged;
if(handler != null) handler(this, e);

Null checks are used since a (event) delegate list is not empty but null if there are no subscribers.
However, it's not thread safe. So it can blow up in your face if you start using a BackgroundWorker or any other multi-threaded technique.
I suggest that you use an empty delegate instead:
public event EventHandler<PriceChangedEventArgs> PriceChanged = delegate {};
Since it allows you to just write:
protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
PriceChanged (this, e);
}
It's thread safe and the code is more easy to read.
why do I care to give it the "this" parameter?!?
Same event handler might be used by multiple event generators. The sender tells which generate the invocation is for. You should always send the correct event generator as it is expected and you'll break open/closed principle if you don't
Why Do I need that method?
You don't, unless you would duplicate code otherwise (such as generating the EventArgs class)

Related

How do I pass objects in EventArgs

I have a usercontrol that raises an event after communicating with a web service. The parent handles this event when raised. What I thought would be the proper approach would be to pass the object returned from the webservice to the parent as eventargs???
If this is the proper way I can't seem to find the instructions on how to do so.
UserControl
public event EventHandler LoginCompleted;
then later after the service returns biz object:
if (this.LoginCompleted != null)
{
this.LoginCompleted(this, new EventArgs() //this is where I would attach / pass my biz object no?);
}
Parent
ctrl_Login.LoginCompleted += ctrl_Login_LoginCompleted;
....snip....
void ctrl_Login_LoginCompleted(object sender, EventArgs e)
{
//get my object returned by login
}
So my question is what would be the "approved" method for getting the user object back to the parent? Create a property class that everything can access and put it there?
You would have to declare your event using EventHandler<T> where T is your class that derives from EventArgs:
public event EventHandler<LoginCompletedEventArgs> LoginCompleted;
LoginCompletedEventArgs could look like this:
public class LoginCompletedEventArgs : EventArgs
{
private readonly YourBusinessObject _businessObject;
public LoginCompletedEventArgs(YourBusinessObject businessObject)
{
_businessObject = businessObject;
}
public YourBusinessObject BusinessObject
{
get { return _businessObject; }
}
}
Usage would be like this:
private void RaiseLoginCompleted(YourBusinessObject businessObject)
{
var handler = LoginCompleted;
if(handler == null)
return;
handler(this, new LoginCompletedEventArgs(businessObject));
}
Please notice how I implemented RaiseLoginCompleted. This is a thread-safe version of raising the event. I eliminates a possible NullReferenceException that can occur in a race condition scenario where one thread wants to raise the event and another thread un-subscribes the last handler after the if check but before actually invoking the handler.
Well, you could do all that or you could define a delegate as your EventHandler and define your properties in its signature.
Such as:
public delegate void MyEventEventHandler(int prop1, string prop2, object prop3...);
public event MyEventEventHandler MyEvent;
I recommend use named tuples with EventHandler<TEventArgs>.
I like olddog's answer. Microsoft already has this delegate EventHandler< TEventArgs >.
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
You don't need to inherits from EventArgs.
Declare your event handler with named tuples.
public event EventHandler<(int id, string message, object LoginObject)> LoginCompleted;
In your client code, assign method to the LoginCompleted event handler
option 1: use lambda
LoginCompleted += (o, e) =>
{
Console.WriteLine($"Hello, sender is {o.ToString()}! id is {e.id}, message is {e.message}, and LoginObject is {e.LoginObject.ToString()}. ");
};
option 2: call a local method
LoginCompleted += onLoginCompleted;
private static void onLoginCompleted (object sender, (int id, string message, object LoginObject) e)
{
Console.WriteLine($"Hello, sender is {sender.ToString()}! id is {e.id}, message is {e.message}, and LoginObject is {e.LoginObject.ToString()}. ");
}
I just wrote an example, please refer to my repo
I personally like Toni Petrina's approach (see https://coderwall.com/p/wkzizq/generic-eventargs-class). It differs from the accepted answer in that you don't have to create a special EventHandler class (e.g. LoginCompletedEventArgs).
(Note: I am using VS 2015 and C# v6. In older versions of Visual Studio and C#, you may have to add using System.Linq;)
Create a generic EventArgs<T> class that inherits from EventArgs...
class EventArgs<T> : EventArgs {
public T Value { get; private set; }
public EventArgs(T val) {
Value = val;
}
}
Declare your event handler...
public event EventHandler<EventArgs<object>> LoginCompleted;
Assuming you have declared and assigned an object named loginObject, add code to raise you event...
private void RaiseLoginCompleted() {
if (LoginCompleted != null)
LoginCompleted(this, new EventArgs<object>(loginObject));
}
In your client code, add the LoginCompleted event handler (uses Linq and calls a local method)...
LoginCompleted += (o, e) => onLoginCompleted(e.Value); // calls a local method
void onLoginCompleted(LoginObject obj) {
// add your code here
}
sometimes it sucks to create a class for merely passing a bool as a derived EventArgs! so you can simply use Action instead of EventHandler. you can pass any type and how many parameters you like (Action supports Up to 16).
class Raiser
{
public event Action<Raiser, bool,DateTimeOffset> OnCreate;
public void Create()
{
OnCreate?.Invoke(this, true,DateTimeOffset.Now);
}
}
class Listener
{
Raiser raiser;
public Listener()
{
raiser = new Raiser();
raiser.OnCreate += Raiser_OnCreate;
}
private void Raiser_OnCreate(Raiser arg1, bool arg2,DateTimeOffset dateTimeOffset)
{
throw new NotImplementedException();//Do Your works here
}
}
generally using Action and 'Func' are easier than Delegate.

.net Event Confusion

I have a data structure class that is a child of a larger data/state class.
The inner data structure fires an event when the contained data changes. This event is consumed by the larger data/state class. The data/state class then fires its own event so that it may pass additional information along to the next event handler.
Public class Data
{
//properties and objects go here
public int Count
{
get { return _count; }
internal set
{
//if the count grew simply set _count
if (value != _oldCount)
{
_oldCount = _count;
_count = value;
}
//if the count shrank then set the count and trigger an event if the count is under 100
else
{
_oldCount = _count;
_count = value;
if (_count < 100)
{
CountChanged(this, new EventArgs());
}
}
}
}
public event EventHandler CountChanged;
}
The above event is consumed by this event handler
Data.CountChanged += new EventHandler(DataCountChanged);
private void DataCountChanged(object sender, EventArgs e)
{
DataRemoved(this, e); //Handle the old event and trigger a new event to pass along more information
}
public event EventHandler DataRemoved;
Finally the second event should be handled by another event handler to do some work. Unfortunately the call to trigger the second event fails with a NullReferenceException more often than not. Why?
----EDIT----
I understand that checking for Null will prevent the exception. The confusion is why this event is Null in the first place =D
You should always raise events using the following pattern to avoid null references and threading issues:
private void DataCountChanged(object sender, EventArgs e)
{
var dr = DataRemoved;
if (dr != null)
{
dr(this, e);
}
}
The reason the handler is null is that it should be viewed as a special collection of delegates. When the collection is empty the delegate has a null value. When you attach one or more handlers the collection is no longer empty and thus is no longer null.
if(DataRemoved != null && DataRemoved.GetInvocationList().Length > 0)
{
}
Assigning an empty delegate to your events may not be such a good design practice. Events are essentially delegates which are like function pointers. In other words, they are just like other reference members in your class. Unless you assign them a value or subscribe to them, they will be and should be null.
The null reference exception you get is for the same reason as declaring private MyClass; and then trying to use it before it has been assigned a value.
When you subscribe to an event, you are essentially telling the event which function to call. If your event does not have at least one such function pointer, it would not be in existence (NULL).
There is a trick to avoid the null check:
Just initialize your event as follows:
public event YourDelegate MyEvent = delegate { };
This way you do not need to check for nulls just call the event as usual:
this.MyEvent("Hi there!");
Edited
To clarify:
Declaring an event like this:
public event Action MyEvent;
It's translated automatically to:
private Action myEvent;
public event Action MyEvent
{
add
{
this.myEvent += value;
}
remove
{
this.myEvent -= value;
}
}
Therefore initializing an event like this:
public event Action MyEvent = delegate { };
It's safe because external code can not assign a null to the event itself.
You can however, assign null to the event inside the class it was declares but what really is happening is that, you are assigning null to the private delegate used by the event.
Source: Jon Skeet, C# In Depth, Events

Is my approach to assign values to an instance of custom EventArgs recommended?

In my current situation I have a class that performs an operation synchronously. During that operation an certain event will the thrown several times, depending on how often the situation where the event is raised occurs.
I know how the event-mechanism works and what the recommended ways of using are. Works well.(Note: My application is single-threaded)
What I want to is, to set a value to a property in my EventArgs. I've never had the need to set properties there.
This is a simplified situation of my current situation: (Note, I don't need answers telling me to use regex, or stringreplace, because that won't work in this situation)
I have this EventArgs:
public class TestEventArgs : EventArgs
{
public String OldString { get; private set; }
public String NewString { get; set; }
public TestEventArgs(String oldString)
{
this.OldString = oldString;
}
}
I do normally raise events this way:
public event EventHandler<TestEventArgs> ChangeString;
protected virtual void OnChangeString(String oldString)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
handler(this, new TestEventArgs(oldString));
}
}
and by calling the OnChangeString method, because I read that this in the way to raise events a long time ago.
Modified code where I need a value of the EventArgs after it's been raised:
public event EventHandler<TestEventArgs> ChangeString;
protected virtual void OnChangeString(TestEventArgs args)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
handler(this, args);
}
}
public void Foo()
{
String oldString = "this is the old string";
// this.OnChangeString(oldString) // this is the way I called before
// now I need to keep a reference to the EventArgs
TestEventArgs args = new TestEventArgs(oldString);
this.OnChangeString(args);
// here I do have full access to args.NewString
}
So, is it ok to keep a reference for the EventArgs and to raise the event with a method that accepts my EventArgs as parameter?
I think your question boils down to:
Is it OK to use the the arguments of an event to communicate data back to the source of the event?
First and foremost: at the low level, this will work. You can modify the event object, and you can see those changes in the code that raises the event.
But what if there are multiple event listeners. Who gets to set NewString?
If you expect only one, it is more clear to pass a delegate (of type Func<String, String>) to the class that now raises the event.
If I get your question right, you generally don't want to keep a reference to your TestEventArg, and reuse this object on another event.
In your case, your TestEventArg has a public properties call NewString. If any event handler updates this property, while it is begin reference by multiple part of your program, you may accidentally running into problem where the NewString property kept changing from another part of your problem.
However, if your TestEventArg has only readable property, then I see no problem keeping the reference and reuse it.
public class TestEventArgs : EventArgs
{
public String OldString { get; private set; }
public String NewString { get; private set; }
public TestEventArgs(String oldString, String newString)
{
this.OldString = oldString;
this.NewString - newString
}
}
In general, you want to keep your event arg immutable which will makes your program easier understand and debug.
Only time I keep the TestEventArg arg (in this case) is if you need access to the variable after the method has been called. Example of this is the OnClosing event for a Form. It has a variable you can set to tell it to cancel the close. In this case, if the client registers the callback, and can set a property on the TestEventArg class, then you'd want to have a variable pointed to it. If all you want to do is pass information to the callback and don't need anything back, then the first method is what I use.
One caveat for me is that if I use the OnChangeString method, I write it so that it encapsulates the details of the event args.
protected virtual void OnChangeString(string oldString)
{
EventHandler<TestEventArgs> handler = this.ChangeString;
if (handler != null)
{
var args = new TestEventArgs(oldString);
handler(this, args);
// Do something with args
}
}

Need help understanding Events in C#

I'm a beginner in C# and having hard times understanding Events in C# .. The book i read (Illustrated C# 2008) gives an example about it , and there are few thing i need to ask about , so i will past the code here and point out the things i don't understand .
public class MyTimerClass
{
public event EventHandler Elapsed;
private void OnOneSecond(object source, EventArgs args)
{
if (Elapsed != null)
Elapsed(source, args);
}
}
class ClassA
{
public void TimerHandlerA(object obj, EventArgs e) // Event handler
{
Console.WriteLine("Class A handler called");
}
}
class ClassB
{
public static void TimerHandlerB(object obj, EventArgs e) // Static
{
Console.WriteLine("Class B handler called");
}
}
class Program
{
static void Main( )
{
ClassA ca = new ClassA(); // Create the class object.
MyTimerClass mc = new MyTimerClass(); // Create the timer object.
mc.Elapsed += ca.TimerHandlerA; // Add handler A -- instance.
mc.Elapsed += ClassB.TimerHandlerB; // Add handler B -- static.
Thread.Sleep(2250);
}
}
Ok, now the line after declaring the event here public event EventHandler Elapsed;
which is private void OnOneSecond(object source, EventArgs args) i know that the two line after it is to check if the event contains methods or not , but what is OnOneSecound for ? or when it's called ? or what it's named .. it's not event handler i guess right ? and what's the relationship between Elapsed and OnOneSecond ?
sorry for the newbie question .. and thanks in advance :)
the OnOneSecond method will be called internally by the MyTimerClass when it needs to invoke the event.
This is a common pattern used by most controls, including the microsoft ones.
Basically you dont need to be checking if the event is set in multiple places, you just do it in this one method then call this method internally to raise the event.
I tend not to pass the event args to the OnXXX method though, for example.
public event EventHandler<EventArgs> SomeEvent;
protected virtual void OnSomeEvent()
{
if (this.SomeEvent !=null)
{
this.SomeEvent.Invoke(this,EventArgs.Empty);
}
}
then to raise it
this.OnSomeEvent();
This is the method, that you call to raise the event safely.
the problem is, you can basically call
Elapsed(source, args)
but if there is noone connected to the event, this will raise a Reference Null exception. as the event is null, when nobody hears on it.
a better solution is, that you directly add a subscriber to the events. then you can safely call it directly. as there will be allways a subscriber.
public event Action<EventArgs> Elapsed = val => { };
(note that with the = its directly assigned. val => { } is a Lambda expression, that defines a empty subscriber.)
Also, look into the Reactive Framework for .net
if you want to do a lot of event stuff, this is the correct solution for it.
That allows you to manually fire the events from thein the class.
That is the standard pattern for raising internal events that's why it is private.
OnOneSecond is just a helper method defined to raise the event. You can use events without such methods, it is just an established pattern to wrap the if (Elapsed != null) check in a method with a name that starts with On...
Technically you could just use Elapsed(source, args) instead of OnOneSecond(source, args), but this will throw NullReferenceException if there are no listeners registered.

In C#, why can't I test if a event handler is null anywhere outside of the class that it's defined?

I am sure that I am just not understanding something fundamental about events and/or delegates in C#, but why can't I do the Boolean tests in this code sample:
public class UseSomeEventBase {
public delegate void SomeEventHandler(object sender, EventArgs e);
public event SomeEventHandler SomeEvent;
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
}
public class UseSomeEvent : UseSomeEventBase {
public bool IsSomeEventHandlerNull() {
// "LEFT HAND SIDE" COMPILER ERROR
return SomeEvent == null;
}
}
class Program {
static void Main(string[] args) {
var useSomeEvent = new UseSomeEvent();
useSomeEvent.SomeEvent +=new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEvent.SomeEvent == null) {
}
var useSomeEventBase = new UseSomeEventBase();
useSomeEventBase.SomeEvent += new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEventBase.SomeEvent == null) {
}
}
static void FuncToHandle(object sender, EventArgs e) { }
}
An event is really just an "add" operation and a "remove" operation. You can't get the value, you can't set the value, you can't call it - you can just subscribe a handler for the event (add) or unsubscribe one (remove). This is fine - it's encapsulation, plain and simple. It's up to the publisher to implement add/remove appropriately, but unless the publisher chooses to make the details available, subscribers can't modify or access the implementation-specific parts.
Field-like events in C# (where you don't specify the add/remove bits) hide this - they create a variable of a delegate type and an event. The event's add/remove implementations just use the variable to keep track of the subscribers.
Inside the class you refer to the variable (so you can get the currently subscribed delegates, execute them etc) and outside the class you refer to the event itself (so only have add/remove abilities).
The alternative to field-like events is where you explicitly implement the add/remove yourself, e.g.
private EventHandler clickHandler; // Normal private field
public event EventHandler Click
{
add
{
Console.WriteLine("New subscriber");
clickHandler += value;
}
remove
{
Console.WriteLine("Lost a subscriber");
clickHandler -= value;
}
}
See my article on events for more information.
Of course the event publisher can also make more information available - you could write a property like ClickHandlers to return the current multi-cast delegate, or HasClickHandlersto return whether there are any or not. That's not part of the core event model though.
You can easily use a very simple approach here to not repeatedly subscribe to an event.
Either of the 2 approaches below can be used:
Flag approach : _getWarehouseForVendorCompletedSubscribed is a private variable initialized to false.
if (!_getWarehouseForVendorCompletedSubscribed)
{
_serviceClient.GetWarehouseForVendorCompleted += new EventHandler<GetWarehouseForVendorCompletedEventArgs>(_serviceClient_GetWarehouseForVendorCompleted);
_getWarehouseForVendorCompletedSubscribed = true;
}
Unsubscribe Approach :Include an unsubscribe everytime you want to subscribe.
_serviceClient.GetWarehouseForVendorCompleted -= new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
_serviceClient.GetWarehouseForVendorCompleted += new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
Here the answer:
using System;
delegate void MyEventHandler();
class MyEvent
{
string s;
public event MyEventHandler SomeEvent;
// This is called to raise the event.
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent();
}
}
public string IsNull
{
get
{
if (SomeEvent != null)
return s = "The EventHandlerList is not NULL";
else return s = "The EventHandlerList is NULL"; ;
}
}
}
class EventDemo
{
// An event handler.
static void Handler()
{
Console.WriteLine("Event occurred");
}
static void Main()
{
MyEvent evt = new MyEvent();
// Add Handler() to the event list.
evt.SomeEvent += Handler;
// Raise the event.
//evt.OnSomeEvent();
evt.SomeEvent -= Handler;
Console.WriteLine(evt.IsNull);
Console.ReadKey();
}
}
Here's a slightly different question
What value is there in testing an externally defined event for null?
As an external consumer of an event you can only do 2 operations
Add a handler
Remove a handler
The null or non-nullness of the event has no bearing on these 2 actions. Why do you want to run a test which provides no perceivable value?
It's a rule in place when using the 'event' keyword. When you create an event, you are restricting outside class interaction with the delegate to a "subscribe / unsubscribe" relationship, this includes cases of inheritance. Remember an event is essentially a property, but for method calls, it isn't really an object itself, so really it looks more like this:
public event SomeEventHandler SomeEvent
{
add
{
//Add method call to delegate
}
remove
{
//Remove method call to delegate
}
}
You'd have to do that from the base class. That's the exact reason that you did this:
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
You can't access events from a derived class. Also, you should make that method virtual, so that it can be overridden in a derived class.
Publisher of the event implicitly overload only += and -= operations, and other operations are not implemented in the publisher because of the obvious reasons as explained above, such as don't want to give control to subscriber to change events.
If we want to validate if a particular event is subscribed in the subscriber class, better publisher will set a flag in its class when event is subscriber and clear the flag when it is unsubscriber.
If subscriber can access the flag of publisher, very easily identifiable whether the particular event is subscriber or not by checking the flag value.

Categories

Resources