Firing events within a plug-in architecture vs single application - c#

I am getting stumped with my plug-in architecture that I am trying to develop with respect to events. I can do this just fine, in a single application: (Obviously this is a very simplified version of what I am trying to accomplish, and if this were my code there are easier ways to accomplish this, just try to follow the logic ;)
public Form1()
{
public event EventHandler OnValueOver5Chars;
Main()
{
OnValueOver5Chars+= new EventHandler(WarnUser);
....
}
private void textBox_Changed( object sender, EventArgs e )
{
if( sender.Text.count() > 5 )
OnValueOver5Chars(sender, e); // WORKS HERE
}
private void WarnUser(object sender, EventArgs e)
{
...
}
}
However, now I have a plug-in architecture, where the plugin implements an interface which houses my event:
// Interface.cs
public interface IPlugin
{
event EventHandler OnValueOver5Chars;
...
}
// Plugin1.cs
public class Plugin1 : IPlugin
{
public event EventHandler OnValueOver5Chars;
Plugin1()
{
OnValueOver5Chars += new EventHandler(Plugin1WarnUser);
}
private void Plugin1WarnUser(object sender, EventArgs e)
{
...
}
}
// Form.cs
public class Form1 : Form
{
public Form1()
{
Assembly SampleAssembly = Assembly.LoadFrom("Plugin1.dll");
Type myType = SampleAssembly.GetTypes()[0];
if (myType.GetInterfaces().Contains(typeof(IPlugin)))
{
IPlugin myInstance = Activator.CreateInstance(myType) as IPlugin;
myInstance.OnValueOver5Chars(this, new EventArgs());
// Compiler Error CS0079 - The event 'event' can only appear on the left hand side of += or -=
}
}
????

You're trying to hook up an event to another event, and that won't work. You need to hook the plug-ins event to a method/delegate. Once you do that, have the method/delegate call the other event.
myInstance.OnValueOver5Chars += OnValueOver5CharsFunc;
...
/*In Form1*/
void OnValueOver5CharsFunc( object sender, EventArgs args )
{
OnValueOver5Chars( sender, args );
}

Events in C# have the property that they are not "callable" directly as methods (or as such as delegates) outside of the class where they are defined.
In your first example you are calling the event from within the class in which you define it. In the second example, however, you are trying to call OnValueOver5Chars from outside the class - hence the error.
To solve this you could consider adding a method to your IPlugin interface (e.g. ValueOver5Chars) that performs OnValueOver5Chars. Note that it is more common to name the event ValueOver5Chars (say), and provide a method OnValueOver5Chars to raise it (i.e. the other way round). See for example the Windows Forms Button class and its Click event.

Related

Subscribing to an event of a base class

I am trying to subscribe to an event that is in my base class but the method in my derived class doesn't seem to trigger whenever that event is triggered. Sample code is below.
public abstract class BaseClass
{
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler Event;
protected virtual void OnEvent(EventArgs ea)
{
if (this.Event!= null)
{
this.Event(null, ea);
}
}
}
public partial class DerivedClass : BaseClass
{
protected override void OnInit(EventArgs e)
{
base.Event+= DoSomething;
}
private void DoSomething(object sender, EventArgs e)
{
//Do Something here.
}
}
BaseClass.OnEvent is called in another control that has the same base class and the derived class where I want to subscribe to is inside another control. Is this possible?
BaseClass.OnEvent is called in another control that has the same base class and the derived class where I want to subscribe to is inside another control. Is this possible?
If you have a derived class and you have two instances of this derived class, the method of instance one won't be called if anything happens in instance two.
In your case you even have two different derived classes, sharing one base class and at runtime you have at least one instance of each derived class, which means, there is no communication between these two.
If you need to link two instances together you have to do something like this:
var instanceOne = new DerivedClassOne();
var instanceTwo = new DerivedClassTwo();
// When something in one happens, let two know:
instanceOne.OnEvent += (sender, e) => instanceTwo.ReactOnOtherChange();

Why the method that fires the C# event must be protected virtual? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
While reading a book on C# I found this source code :
public class Stock
{
...
public event EventHandler<PriceChangedEventArgs> PriceChanged;
protected virtual void OnPriceChanged (PriceChangedEventArgs e)
{
if (PriceChanged != null) PriceChanged (this, e);
}
}
The author states that the standard event pattern requires, I quote :
The pattern requires that you write a protected virtual method that fires the event. The name must match the name of the event, prefixed with the word On, and then accept a single EventArgs argument:
Why should it be protected and virtual ?
It's a pattern from the days of "Component-oriented programming" - it's still valid, but
not as relevant today as Delegate-based events which use the OnEventName-pattern aren't as popular because UI programming is either done in JavaScript (thus avoiding .NET entirely) or uses the ViewModel-pattern which doesn't use Delegate events at all.
As an explanation for "why" - let's look at the canonical example of Component-oriented programming: WinForms controls. All controls derive from System.Windows.Forms.Control which represents an ecapsulation of a Win32 "hWnd" window, which is a 2D surface which accepts Win32 Window Messages for user-input (mouse, keyboard, touch, etc) and paints to itself.
The Control class exposes its own initial set of events, like Load and MouseMove. All of these events are exposed in two ways:
Publicly accessible event members. Essentially multicast, strongly-typed Delegate properties.
These are subscribe-only. So a consumer of a component can listen to events, but they cannot invoke events themselves.
In C# they look like this:
public event DelegateType EventName;
For example:
public class Control : Component
{
public event EventHandler Click;
}
Methods that invoke each event (by invoking the multicast Delegate).
These methods are not public because that would break encapsulation (i.e. you don't want a consumer to be able to raise events), so they can be either private or protected.
By choosing protected instead of private means that subclasses can invoke events themselves, if appropriate.
In C# they look like this:
public class Control : Component
{
public event EventHandler Click;
protected virtual void OnClick(EventArgs e)
{
this.Click?.Invoke( this, e );
}
private void OnWin32WindowMessage( Message m )
{
switch( m.EventId )
{
case Win32.MouseClick:
this.OnClick( EventArgs.Empty );
break;
case Win32.MouseMove:
this.OnMouseMove( EventArgs.Empty );
break;
case Win32.KeyDown:
this.OnKeyDown( EventArgs.Empty );
break;
// etc
}
}
}
You can argue that if a component subclass only wants to subscribe to events belonging to its superclass then it should not be able to invoke certain events themselves and so the On{EventName} methods should be private and not protected - and the subclass should set-up an EventHandler inside its constructor. Like so:
public class MySubclass : Control
{
public MySubclass()
{
this.Click += new EventHandler( this.Clicked );
}
private void Clicked(Object sender, EventArgs e)
{
MessageBox.Show( "boop!" );
}
}
...and this is valid.
However, there are at least three reasons for using protected virtual methods instead of private:
The advantage to using virtual methods is that it lets the subclass override the behaviour.
For example, if the superclass has a trivial OnClick method that simply (and always) invokes the Click event but you want your subclass to only allow the Click event to be invoked if this.Disabled == true):
public class MySubclass : Control
{
protected override OnClick( EventArgs e )
{
if( !this.Disabled )
{
base.OnClick( e );
}
}
public Boolean Disabled { get; set; }
}
Allowing subclasses to be notified first.
Multicast delegates in C# do not offer any control over the precise order-of-execution - by using virtual methods this allows a subclass to always be notified first, before any external consumers. This is important if the state of MySubclass will change in an event-handler. For example:
public class MySubclass : Control
{
public MySubclass()
{
this.Click += new EventHandler( this.Clicked );
}
private void Clicked(Object sender, EventArgs e)
{
this.BackgroundColor = Colors.Red;
}
}
public class MyForm : Form
{
private readonly MySubclass sc;
public MyForm()
{
this.sc = new MySubclass();
this.Controls.Add( this.sc );
this.sc.Click += new EventHandler( this.SCClicked );
}
private void SCClicked (Object sender, EventArgs e)
{
MessageBox.Show( "The control's colour is " + this.sc.BackgroundColor );
}
}
As it's possible for MyForm.SCClicked to run before MySubclass.Clicked, SCClicked may report the old colour, not the new colour.
By using a virtual method override this can be avoided:
public class MySubclass : Control
{
protected override void OnClick(EventArgs e)
{
this.BackgroundColor = Colors.Red;
base.OnClick( e );
}
}
public class MyForm : Form { /* unchanged */ }
...and it will now work as-expected.
The other reason is performance.
Delegates are more expensive than a virtual method call. So by overriding the method means a subclass can subscribe to an event with less runtime overhead than using an event-handler.
While this isn't important for one-off events like Load or maybe even Paint and Click, it can matter if it's a high-frequency event (think: thousands of times per second).
Performance can matter, even on today's computers that are 10-50x faster than the late-1990s machines that were around when .NET and WinForms was originally designed. Especially as event-handling code in WinForms has to run in the UI thread.
Today, high-frequency events tend to use the Observer pattern instead of Delegate events, precisely because that avoids the overhead of using delegates (the linked Wikipedia article does describe C#'s event support as an example of the Observer pattern, which is strictly true - but when people talk about the Observer pattern they usually mean something like Reactive programming: http://reactivex.io/
virtual means that a class can inherit from Stock and override that method.
protected means that only Stock or classes that inherit from Stock can access that method.
Events by themselves don't have to be fired from virtual or protected methods. This is just a pattern that some applications use, which allow derived classes to fire the event as well.
Classes that inherit from Stock and override OnPriceChanged can call base. OnPriceChanged and It would fire the event.
For example,
class MyStock : Stock
{
protected override void OnPriceChanged (PriceChangedEventArgs e)
{
// Do something
base.OnPriceChanged(e); // will call OnPriceChanged in the base class, and fire the event
}
}

Passing an event handler as argument in C#

I'm writing down a customized Timer, that extends DispatcherTimer. It has a method called TimerSetUp, in which I associate the Tick event to an EventHandler.
public class MyTimer : DispatcherTimer
{
public MyTimer(){}
public void TimerSetUp(EventHandler<EventArgs> _EventHandler)
{
base.Tick += _EventHandler;
}
}
I have now another couple of classes, StopwatchTimer and CountdownTimer, that extend MyTimer. Let's look at CountdownTimer.
public class CountdownTimer : MyTimer
{
public CountdownTimer()
{
base.TimerSetUp(CountdownTimer_Tick);
}
public void CountdownTimer_Tick(object sender, EventArgs e)
{
//...do something
}
}
When either of them is declared, the constructor must call the base class method TimerSetUp and just set up the event handler.
The problem is that, in the signature of the TimerSetUp function, it gives me this error
Cannot implicitly convert type 'System.EventHandler<System.EventArgs>'
to'System.EventHandler<object>
And I can't get rid of it. If I just put TimerSetUp inside CountdownTimer, and just assign directly the event handler, like this
base.Tick += CountdownTimer_Tick;
it works, but I'd really like to make it work the other way.
So I'd like to know if
1) There's a way I can resolve this
2) Is this a good approach to extensibility of the code?
Nevermind, I made it. I just casted a generic object in the function signature and wrapped a new eventHandler inside the code.
public void TimerSetUp(EventHandler<object> _EventHandler)
{
base.Tick += new EventHandler<object>(_EventHandler);
}
DispatchTimer.Tick seems to be the non generic EventHandler rather than EventHandler<EventArgs>. Since you are using the base EventArgs anyway, they are functionally equivalent:
public void TimerSetUp(EventHandler _EventHandler)
{
base.Tick += _EventHandler;
}
See: https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer.tick(v=vs.110).aspx

Delegates and Events with multiple classes

This has taken me quite a few days to develop a demo of communicating between classes with delegates and events. I would like to know if this is the best practices way of accomplishing this passing of data between classes or not. If there is a better method please let me know. Specifically, if something happens in a subclass how do you get it back to the main class. This would be particularly useful when doing n-tier architecture by separating out the User Interface from the Business Logic Level, and the Data Access Level.
I have a form that has 3 text boxes: tb1, tb2, and tbAnswer.
I also have a button that says "Add" and it is just button1.
The main form is:
namespace DelegateTest
{
public delegate void ShowMessage(object sender, Form1.AnswerEventArgs e);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void a_OnShowMessage(object sender, AnswerEventArgs e)
{
tbAnswer.Text = e.answer;
}
public class AnswerEventArgs :EventArgs
{
public string answer { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
AddClass a = new AddClass();
a.OnShowMessage += new ShowMessage(a_OnShowMessage);
a.AddMe(Convert.ToInt16(tb1.Text), Convert.ToInt16(tb2.Text));
}
}
}
and the subform called AddClass.cs is:
namespace DelegateTest
{
class AddClass
{
public event ShowMessage OnShowMessage;
public void AddMe(int a, int b)
{
Form1.AnswerEventArgs e = new Form1.AnswerEventArgs();
e.answer = (a+b).ToString();
OnShowMessage(this, e);
}
}
}
Your approach is sound except for two details.
First, a NullPointerException will occur if your event is raised before any handlers are added. You can get around this in one of two ways.
1) Make a local copy (to avoid race condition) and check it for null:
var showMessage = OnShowMessage;
if (showMessage != null)
{
showMessage(this, e);
}
2) Initialize your event to an empty delegate:
public event ShowMessage OnShowMessage = delegate { };
Second, you do not need to declare your own delegate in this case. You can simply create a standard EventHandler with your own event args:
public event EventHandler<Form1.AnswerEventArgs> OnShowMessage = delegate { };
See How to: Publish Events that Conform to .NET Framework Guidelines for more information.

Why events can't be used in the same way in derived classes as in the base class in C#?

In following code, I want to extend the behaviour of a class by deriving/subclassing it, and make use of an event of the base class:
public class A
{
public event EventHandler SomeEvent;
public void someMethod()
{
if(SomeEvent != null) SomeEvent(this, someArgs);
}
}
public class B : A
{
public void someOtherMethod()
{
if(SomeEvent != null) SomeEvent(this, someArgs); // << why is this not possible?
//Error: The event 'SomeEvent' can only appear on the left hand side of += or -=
//(except when used from within the type 'A')
}
}
Why isn't it possible?
And what is the common solution for this kind of situation?
Others have explained how to get round the issue, but not why it's coming up.
When you declare a public field-like event, the compiler creates a public event, and a private field. Within the same class (or nested classes) you can get at the field directly, e.g. to invoke all the handlers. From other classes, you only see the event, which only allows subscription and unsubscription.
The standard practice here is to have a protected virtual method OnSomeEvent on your base class, then call that method in derived classes. Also, for threading reasons you will want to keep a reference to the handler before checking null and calling it.
For an explanation of the why read Jon Skeet's answer or the C# specification which describes how the compiler automatically creates a private field.
Here is one possible work around.
public class A
{
public event EventHandler SomeEvent;
public void someMethod()
{
OnSomeEvent();
}
protected void OnSomeEvent()
{
EventHandler handler = SomeEvent;
if(handler != null)
handler(this, someArgs);
}
}
public class B : A
{
public void someOtherMethod()
{
OnSomeEvent();
}
}
Edit: Updated code based upon Framework Design Guidelines section 5.4 and reminders by others.
Todd's answer is correct. Often you will see this implemented throughout the .NET framework as OnXXX(EventArgs) methods:
public class Foo
{
public event EventHandler Click;
protected virtual void OnClick(EventArgs e)
{
var click = Click;
if (click != null)
click(this, e);
}
}
I strongly encourage you to consider the EventArgs<T>/EventHandler<T> pattern before you find yourself making all manner of CustomEventArgs/CustomEventHandler for raising events.
The reason the original code doesn't work is because you need to have access to the event's delegate in order to raise it, and C# keeps this delegate private.
Events in C# are represented publicly by a pair of methods, add_SomeEvent and remove_SomeEvent, which is why you can subscribe to an event from outside the class, but not raise it.
My answer would be that you shouldn't have to do this.
C# nicely enforces Only the type declaring/publishing the event should fire/raise it.
If the base class trusted derivations to have the capability to raise its events, the creator would expose protected methods to do that. If they don't exist, its a good hint that you probably shouldn't do this.
My contrived example as to how different the world would be if derived types were allowed to raise events in their ancestors. Note: this is not valid C# code.. (yet..)
public class GoodVigilante
{
public event EventHandler LaunchMissiles;
public void Evaluate()
{
Action a = DetermineCourseOfAction(); // method that evaluates every possible
// non-violent solution before resorting to 'Unleashing the fury'
if (null != a)
{ a.Do(); }
else
{ if (null != LaunchMissiles) LaunchMissiles(this, EventArgs.Empty); }
}
virtual protected string WhatsTheTime()
{ return DateTime.Now.ToString(); }
....
}
public class TriggerHappy : GoodVigilante
{
protected override string WhatsTheTime()
{
if (null != LaunchMissiles) LaunchMissiles(this, EventArgs.Empty);
}
}
// client code
GoodVigilante a = new GoodVigilante();
a.LaunchMissiles += new EventHandler(FireAway);
GoodVigilante b = new TriggerHappy(); // rogue/imposter
b.LaunchMissiles += new EventHandler(FireAway);
private void FireAway(object sender, EventArgs e)
{
// nuke 'em
}
Wrap it with a protected virtual On... method:
public class BaseClass
{
public event EventHandler<MyArgs> SomeEvent;
protected virtual void OnSomeEvent()
{
if(SomeEvent!= null)
SomeEvent(this, new MyArgs(...) );
}
}
Then override this in a derived class
public class DerivedClass : BaseClass
{
protected override void OnSomeEvent()
{
//do something
base.OnSomeEvent();
}
}
You'll set this pattern all over .Net - all form and web controls follow it.
Do not use the prefix Raise... - this is not consistent with MS's standards and can cause confusion elsewhere.

Categories

Resources