I want an abstract class that raises an event, this event will be raised by the concrete class.
What I want is when I use another class to listen to these events the signature of the delegate should have the concrete type not the abstract, I don't want to cast it.
For the moment I have come up with this solution. It works but I don't find it particularly clever especially because of the "STUPID, DOESN'T MAKE SENSE......" part.
Here is my solution :
public delegate void ClassAEventHandler<TClassA>(TClassA classA) where TClassA : ClassA;
//Abstract class that raise Event
public abstract class ClassA<TClassA> : where TClassA : ClassA
{
public event ClassAEventHandler<TClassA> onClassEventRaised;
private TClassA eventClassA;
public void registerEventClass(TClassA classA)
{
this.eventClassA = classA;
}
public void raiseClassEvent()
{
this.onClassEventRaised(this.eventClassA);
}
}
// Exemple of concrete type
public class ClassB : ClassA<ClassB> // <------ IT SEEMS DUMB
{
public void action()
{
//Do something then raise event
this.raiseClassEvent();
}
public void saySomething() {};
}
// Exemple of concrete type
public class ClassC : ClassA<ClassC> // <------ IT SEEMS DUMB
{
public void command()
{
//Do something then raise event
this.raiseClassEvent();
}
public void destroySomething() {};
}
//Class that listen to the event raised
public class MyEventListener
{
private ClassB classB;
private ClassC classC;
public MyEventListener()
{
this.classB = new ClassB();
this.classB.registerEventClass(this.classB); // <------ STUPID, DOESN'T MAKE SENSE......
this.classB.onClassEventRaised += classB_onClassEventRaised;
this.classC = new ClassC();
this.classC.registerEventClass(this.classC); // <------ STUPID, DOESN'T MAKE SENSE......
this.classC.onClassEventRaised += classC_onClassEventRaised;
}
public void classB_onClassEventRaised(ClassB classB)
{
classB.saySomething();
}
public void classC_onClassEventRaised(ClassC classC)
{
classC.destroySomething();
}
//What i don't want
/*
public void classB_onClassEventRaised(ClassA classA)
{
((classB)classA).saySomething();
}
*/
}
First of all, you're not following regular event design in .NET.
Instead of implementing your own delegate, use EventHandler<TArgs>, and create a derived class of EventArgs.
Your CustomEventArgs should have a T generic parameter:
public class CustomEventArgs<T> where T : A
{
private readonly T _instance;
public CustomEventArgs(T instance)
{
_instance = instance;
}
public T Instance { get { return _instance; } }
}
Also, don't implement a custom way of registering events. If you want to encapsulate how handlers are added to the event, you need to use event accessors.
Finally, you could implement your classes as follows:
public class A<T> where T : A
{
private event EventHandler<CustomEventArgs<T>> _someEvent;
// An event accessor acts like the event but it can't be used
// to raise the event itself. It's just an accessor like an special
// event-oriented property (get/set)
public event EventHandler<CustomEventArgs<T>> SomeEvent
{
add { _someEvent += value; }
remove { _someEvent -= value; }
}
protected virtual void RaiseSomeEvent(CustomEventArgs<T> args)
{
// If C# >= 6
_someEvent?.Invoke(this, args);
// Or in C# < 6
// if(_someEvent != null) _someEvent(this, args);
}
}
public class B : A<B>
{
public void DoStuff()
{
// It's just about raising the event accessing the whole
// protected method and give an instance of CustomEventArgs<B>
// passing current instance (i.e. this) to CustomEventArgs<T>
// constructor.
RaiseSomeEvent(new CustomEventArgs<B>(this));
}
}
Now, if you try to handle SomeEvent, you'll get the CustomEventArgs<B> typed as B instead of A:
B b = new B();
b.SomeEvent += (sender, args) =>
{
// args.Instance is B
B instance = args.Instance;
};
b.DoStuff(); // Raises SomeEvent internally
Related
I want to be able to have an object add one of its methods to an EventHandler that is passed to it and give said method the ability to remove itself from the EventHandler.
public class EventRaiser {
public event EventHandler event1
public event EventHandler event2
public void fire() {
event1?.Invoke(this, null);
event2?.Invoke(this, null);
}
}
public class EventSubscriber {
EventHandler eh;
public EventSubscriber(EventHandler eh) {
this.eh = eh;
eh += receive;
}
public void receive(object obj, EventArgs data) {
// Do stuff.
if(condition) eh -= receive;
}
}
public class MainClass {
public void Main() {
EventRaiser er = new EventRaiser();
EventSubscriber es1 = new EventSubscriber(er.event1);
EventSubscriber es2 = new EventSubscriber(er.event2);
er.fire();
}
}
The above code does not compile as I cannot even pass er.event1 or er.event2 to EventSubscriber ("The event can only appear in the left hand side of +=..."). Removing the event keyword from the EventHandlers fixes this issue but unsubscribing does not work properly. Is there a way to make this work? Use pointers maybe?
The problem here comes from you passing an EventHandler, not the list holding the delegates behind it itsself. Basically the "list of method pointers" to your handlers.
As you can see, in the declaration of event1 you have the keyword event, which is missing when you pass it somewhere else.
Unfortunately you cannot extract the "delegate holder" of an event easily.
Basically at the time you want to register your handler to an event you somehow need a compile time reference to it, in order to be able to += and -= to it.
You could do the following:
public class EventRaiser
{
public delegate void Event1(string args);
public List<Event1> handlers = new List<Event1>();
public void register(Event1 handler)
{
handlers.Add(handler);
}
public void unregister(Event1 handler)
{
handlers.Remove(handler);
}
public void fire()
{
handlers.ForEach(handler => handler("myEventArgs"));
}
}
public class EventSubscriber
{
Action<Event1> registerAction;
Action<Event1> unregisterAction;
public EventSubscriber(Action<Event1> register, Action<Event1> unregister)
{
registerAction = register;
unregisterAction = unregister;
registerAction(receive);
}
public void receive(string args)
{
// Do stuff.
unregisterAction(receive);
}
}
public class MainClass
{
public void Main()
{
EventRaiser er = new EventRaiser();
EventSubscriber es1 = new EventSubscriber(er.register, er.unregister);
er.fire();
}
}
I would like to create event actions to notify other classes when something happened. So my current flow looks like this
For testing purposes I created this code
Program.cs
Instantiate the first class and call a method from it (constructor is fine).
internal class Program
{
private static void Main(string[] args)
{
First f = new First();
}
}
First.cs
Instantiate the second class and call a method from it (constructor is fine). Listen for an event of the second class when some data has changed.
internal class First
{
public First()
{
// ...
Second s = new Second();
s.Updated += OnSecondUpdated;
}
private void OnSecondUpdated()
{
Console.WriteLine("Done");
Console.ReadLine();
}
}
Second.cs
Instantiate the third class and call a method from it (constructor is fine). Listen for an event of the third class when some data has changed and raise the own one.
internal class Second
{
public event Action Updated;
public Second()
{
// ...
Third t = new Third();
t.Updated += OnThirdUpdated;
}
private void OnThirdUpdated()
{
// ...
Updated();
}
}
Third.cs
Raise an event when some data has changed.
internal class Third
{
public event Action Updated;
public Third()
{
// ...
Updated();
}
}
Unfortunately the event variables are null. How can I instantiate these variables properly?
The problem here is that you're trying to do this in the constructor, where at that time nothing has (yet) been assigned to the Updated event. You can "solve" this by checking for null:
internal class Third
{
public event Action Updated;
public Third()
{
// ...
if(Updated != null)
Updated();
}
}
But it wont mean your code now "works" as you only assign the event a handler after constructor has been called:
Third t = new Third();
t.Updated += OnThirdUpdated;
So one possible solution for this pattern is to NOT do this raising of the event in the constructor, and instead defer the logic to another method.
internal class Third
{
public event Action Updated;
public Third()
{
}
public void Init()
{
// ...
if(Updated != null)
Updated();
}
}
Third t = new Third();
t.Updated += OnThirdUpdated;
t.Init();
You call the Update() before the classes can subscribe to the events, due to the constructor of the underlying object being called first. I changed it so that the constructor takes the related class and subscribes the event itself.
internal class First
{
public First()
{
Second s = new Second(this);
}
internal void OnSecondUpdated()
{
Console.WriteLine("Done");
Console.ReadLine();
}
}
internal class Second
{
public event Action Updated;
public Second(First f)
{
Updated += f.OnSecondUpdated;
Third t = new Third(this);
}
internal void OnThirdUpdated()
{
Updated();
}
}
internal class Third
{
public event Action Updated;
public Third(Second s)
{
Updated += s.OnThirdUpdated;
Updated();
}
}
with the code posted below I want to update progressbar from foo1.
but I'm unable to implement eventhandler in Foo
class Foo : Form // implements progressbar
{
IFoo foo = new Foo1()
// this will not do:
ProgressBarEventHandler = new EventUpdateProgressBar(this.UpdateProgressBar);
UpdateProgressBar() { }
}
public delegate void EventUpdateProgressBar();
class FooBase
{
public EventUpdateProgressBar ProgressBarEventHandler;
protected virtual void UpdateProgressBar()
{
if (ProgressBarEventHandler != null)
ProgressBarEventHandler();
}
}
class Foo1 : IFoo,FooBase { base.UpdateProgressBar() }
class Foo2 : IFoo,FooBase {}
interface IFoo {}
is there a way to get this working or is there a better approach ?
I'm not completely sure what your intent was, but if you're trying to implement two classes, one of which raises events while the other handles them, then the minimal sample would look as follows.
delegate void MyEvent();
class MyEventSource
{
public event MyEvent Event;
public void RaiseEvent()
{
MyEvent evt = Event;
if (evt != null)
evt();
}
}
class MyEventListener
{
public void SubscribeForEventFromMyEventSource(MyEventSource eventSource)
{
eventSource.Event += this.EventHandler;
}
public void EventHandler()
{
// Event handling logic here
}
}
More reading on events is available here: https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx and here https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/
I have the following scenario:
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
...
}
public class SomeClass : SomeBaseClass
{
public void DoSomething()
{
//TODO
if (SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
SomeBaseClass has an event which needs to be called in a base class, however this it isn't possible to directly call the event from a base class. To get around this, I can override the event in the base class, like so:
public class SomeClass : SomeBaseClass
{
new public event EventHandler SomeEvent;
This is fine I guess, however my question is whether there is some kind of universal method, or good practice for implementing the functionality above?
The fact that it isn't possible to call an event from a base class suggests that I shouldn't really be doing this in the first place, perhaps the responsibility of calling the event should be only in SomeBaseClass?
That isn't allowed indeed. If I may recommend an alternative approach:
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
protected void RaiseSomeEvent(EventArgs e)
{
var eh = SomeEvent;
if (eh != null)
eh(this, e);
}
}
public class SomeClass : SomeBaseClass
{
public void DoSomething()
{
//TODO
RaiseSomeEvent(EventArgs.Empty);
}
}
Note that I have moved the invocation of the event handler to the owning class, this is required by .NET / C# since only that class can invoke the event handler. Second, I have made the event handler thread safe by assigning it to eh first.
Never hide the base class' event by using the new keyword! You will get unexpected results when you use the base class' type as type for a variable or when the base class invokes the event.
I would stay away from using new mainly because code will behave differently if an object is cast to the base class. Here's an alternative implementation:
public abstract class SomeBaseClass
{
public virtual event EventHandler SomeEvent;
protected virtual void HandleSomeEvent()
{
var ev = SomeEvent; // Localize event field used
if (ev != null)
{
ev(this, EventArgs.Empty);
}
}
}
public class SomeClass : SomeBaseClass
{
public override event EventHandler SomeEvent
{
add { base.SomeEvent += value; }
remove { base.SomeEvent -= value; }
}
protected override void HandleSomeEvent()
{
base.HandleSomeEvent();
// ... My own code here
}
}
This allows for a great deal of flexibility. You can provide some implementation of event handling as well as allow the implementer to completely override the base class implementation.
public delegate void ErrorHandler(string result);
public class BaseClass
{
public event ErrorHandler OnError;
protected void RaiseErrorEvent(string result)
{
OnError?.Invoke(result);
}
}
public class SampleClass:BaseClass
{
public void Error(string s)
{
base.RaiseErrorEvent(s);
}
}
I personally prefer to use delegates for that :
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
protected Action<object, EventArgs> SomeEventInvoker;
public SomeBaseClass()
{
SomeEventInvoker = new Action<object, EventArgs>((sender, args) =>
{ if (SomeEvent != null) SomeEvent(sender, args); });
}
}
public class SomeClass : SomeBaseClass
{
public SomeClass()
{
DoSomething();
}
public void DoSomething()
{
SomeEventInvoker(this, new EventArgs());
}
}
Consider the following constellation.
public delegate void BarHandler(Foo sender, FooEventArgs<Object> args);
public delegate void BarHandler<T>(Foo<T> sender, FooEventArgs<T> args);
public interface Foo
{
Object Value
{ get; }
event BarHandler BarEvent;
void Update();
}
public interface Foo<T> : Foo
{
new T Value
{ get; }
new event BarHandler<T> BarEvent;
}
public class Baz<T> : Foo<T>
{
Object Foo.Value
{ get { return Value; } }
public T Value
{ get; set; }
private BarHandler handler;
event BarHandler Foo.BarEvent
{
add{ handler += value; }
remove{ handler -= value; }
}
public event BarHandler<T> BarEvent;
public void Update()
{
BarEvent(this, new FooEventArgs<T>());
(this as Foo).BarEvent(this, new FooEventArgs<Object>());
}
}
I have a Interface and a Generic Interface which extends the first Interface and a class that extends the generic Interface. The generic interface hides the not generic one, via the new keyword.
The Update method should raise both, the not-generic and the generic one. And that is the problem I am dealing with at the moment.
The resulting error is:
The event BarEvent can only appear on the left hand side of += or -= when used outside of Foo.
But I am in Foo, or do I miss something?
So, what I want is, regardless on which event the client has been registerd, it should be notified. I also should mention, that both, add and remove must work, so there is no option with delegates or something like that.
Just use the private handler variable, this should do the trick.
public void Update()
{
BarEvent(this, new FooEventArgs<T>());
handler(this, new FooEventArgs<Object>());
}
It would probably also be a good idea to check BarEvent and handler for null.