Opennetcf.IOC event subscription and inheritance - c#

Class1 has event with attribute [EventPublication("event1")].
Class2 and Class3 inherits from Class1.
I want to subscribe Method1 to event in object from Class2 and Method2 to event in object from Class3 using [EventSubscription].
But in the derived classes there is the same EventPublication name of the event. So how to distinguish events in derived classes? Is it possible?
EDIT:
Maybe I misunderstand some obvious things about IoC or I try to complicate simple solution...
I will try to clarify my question. Here is some code:
class BasePresenter
{
[EventPublication("event")]
public event Action action;
public void Run()
{
someAction();
if (action != null)
action();
}
protected virtual void someAction()
{
}
}
class Presenter1 : BasePresenter
{
protected override void someAction()
{
}
}
class Presenter2 : BasePresenter
{
protected override void someAction()
{
}
}
class AnotherClass
{
[EventSubscription("event", ThreadOption.Caller)]
public void action1()
{
System.Windows.Forms.MessageBox.Show("Presenter1 started");
}
[EventSubscription("event", ThreadOption.Caller)]
public void action2()
{
System.Windows.Forms.MessageBox.Show("Presenter2 started");
}
}
There is action1() and action2() methods in Another class. I would like to fire action1() when instance of Presenter1 Run() method is called and fire action2() when instance of Presenter2 Run() method is called. But calling Run() method will fire both methods action1 and action2.

I'm not certain I understand the question. There are two ends to the event aggregation, a Publisher and a Subscriber. They are "connected" by the string event name you use in the attribute and nothing else.
A subscription can be done in the same class as the publication, though it's not clear to me why you'd ever do that, just have the base class call a virtual method that the derived classes implement and you're done.
If you want to use events and you want to know if the event source instance is not the receiver instance, just check the event's source input parameter against this, something along these lines:
[EventSubscription("myevent")]
public void OnEvent(object sender, EventArgs a)
{
if(sender.Equals(this)) return;
// do stuff here - the event came from another class instance
}

Related

Declare a static event in an interface and raise in the implementation

public interface IProgress
{
public static event Action<IProgress> EvtSpawned;
}
public class PlayerSingle : MonoBehaviour, IProgress
{
private void Start()
{
IProgress.EvtSpawned?.Invoke(this);
}
}
I basically want to be able to have some classes listen to whenever an instance is created that implements IProgress. I can subscribe to the event above, but it seems there is no way for me to raise it, it just throws an error even when using within a class that implements IPgrogress.
For now, I just use static events in classes that implement it one by one.
Events can be invoked only by the "owners" i.e. IProgress interface in this case. Not sure why do you require such structure (the provided description is not enough for me) but if you really need to you can declare an invoke method on the interface to delegate the event invocation:
public interface IProgress
{
public static event Action<IProgress> EvtSpawned;
public static void Invoke(IProgress inv) => EvtSpawned?.Invoke(inv);
}
public class PlayerSingle : IProgress
{
private void Start()
{
IProgress.Invoke(this);
}
}

Observer pattern in C# / how to make a Form an observer

I fail to find an answer so far, probably just lacking the appropriate keywords to search for.
I want to implement an Observer Pattern in C#, so any Observer object can subscribe to a Subject object and then receives all its notifications. Then it decides based on the Notification type whether it's important or not.
public class Subject
{
private List<Observer> observers;
public void AttachObserver(Observer Observer)
{
this.observers.Add(Observer);
}
public void DetachObserver(Observer Observer)
{
this.observers.Remove(Observer);
}
public void NotifyObservers(CommonNotification Notification) // who we are, what kind of notification, bla bla
{
foreach(Observer Observer in observers)
{
Observer.OnNotify(Notification);
}
}
}
public class Observer
{
public abstract void OnNotify(CommonNotification Notification);
}
So any object wanting to subscribe to a Subject needs to be an inheritance of the Observer class. But how to do that? My MainForm is based on Form. If I replace the Observer class with a general object it won't implement an OnNotify() event.
What's the point I am missing here? I know I should properly implement it using Event handlers but in order to learn how basic design patterns work I rather implement things myself first.
Short Answer: look at first answer to this question: Super-simple example of C# observer/observable with delegates
I understand you wanting to try and implement it yourself but delegates and events are really the natural fit here (and are in fact an implemention of the observer pattern built into c#).
If still want to do it yourself I would recommend using interfaces instead of abstract/concrete classes.
public interface ISubject
{
void AttachObserver(IObserver observer);
void DetachObserver(IObserver observer);
void NotifyObservers(CommonNotification Notification);
}
public interface IObserver
{
void OnNotify(CommonNotification Notification);
}
Your form could then implement IObserver (or ISubject or both!!).
public class MyForm : Form, IObserver
{
...
}
you can use Interface instead of abstract class like this
public Interface IObserver
{
public void OnNotify(CommonNotification Notification);
}
....
public class MyForm:Form, IObserver {
....
}
You should replace your Observer class with an Interface:
public Interface IObserver
{
public void OnNotify(CommonNotification Notification);
}
Then your mainform (or anything else) can implement IObserver
You can implement it very easily using event. I am giving a sample code -
public class MyForm : Form
{
public event Action btn1Clicked;
private void button1_Click(object sender, EventArgs e)
{
btn1Clicked();
}
}
public abstract class AbsObserver
{
protected MyForm Form;
public AbsObserver(Subject subject)
{
subject.Attach(OnNotify);
Form = new MyForm();
Form.btn1Clicked += Form_btn1Clicked;
}
void Form_btn1Clicked()
{
Console.WriteLine("Do button click task");
}
public abstract void OnNotify();
}
public class Observer1 : AbsObserver
{
public Observer1(Subject subject)
: base(subject)
{
}
public override void OnNotify()
{
Console.WriteLine("observer1 notified");
}
}
public class Observer2 : AbsObserver
{
public Observer2(Subject subject)
: base(subject)
{
}
public override void OnNotify()
{
Console.WriteLine("observer2 notified");
}
}
public class Subject
{
private event Action Notify;
public void Attach(Action a)
{
Notify += a;
}
private void NotifyAll()
{
Notify();
}
}
Here forms are not observers. The observers have the object of form and all form related issues are handled by the observers. This is kind of composting.

C# How to create a Singleton that publishes events & Classes that subscribe?

Goal: Have a singleton publish events and allow any class to subscribe/listen to those events
Problem: I cannot figure out how to do this. The code below is illegal but it purveys what I'm trying to do
TransmitManager Class - Publisher
//Singleton
public sealed class TransmitManager
{
delegate void TransmitManagerEventHandler(object sender);
public static event TransmitManagerEventHandler OnTrafficSendingActive;
public static event TransmitManagerEventHandler OnTrafficSendingInactive;
private static TransmitManager instance = new TransmitManager();
//Singleton
private TransmitManager()
{
}
public static TransmitManager getInstance()
{
return instance;
}
public void Send()
{
//Invoke Event
if (OnTrafficSendingActive != null)
OnTrafficSendingActive(this);
//Code connects & sends data
//Invoke idle event
if (OnTrafficSendingInactive != null)
OnTrafficSendingInactive(this);
}
}
Test Class - Event Subscriber
public class Test
{
TrasnmitManager tm = TransmitManager.getInstance();
public Test()
{
//I can't do this below. What should my access level be to able to do this??
tm.OnTrafficSendingActive += new TransmitManagerEventHandler(sendActiveMethod);
}
public void sendActiveMethod(object sender)
{
//do stuff to notify Test class a "send" event happend
}
}
You shouldn't need to make the events static.
public event TransmitManagerEventHandler OnTrafficSendingActive;
public event TransmitManagerEventHandler OnTrafficSendingInactive;
Either your events have to be instance members or you have to address them as static.
TransmitManager.OnTrafficSendingActive +=...
OR
public event TransmitManagerEventHandler OnTrafficSendingActive;
...
TransmitManager.Instance.OnTrafficSendingActive+=...
Also: use EventHandler as your event delegate. Consider making a custom arguments class and pass the status to just one event instead of multiple events. This will let you pass status messages as well.

Wrong Derived Class Methods Execution on Event?

public Class A
{
public A()
{
someotherclass.someevent += new EventHandler(HandleEvent);
}
private void HandleEvent(object sender,CustomEventArgs e)
{
if(e.Name == "Type1")
Method1();
else if(e.Name == "Type2")
Method2();
}
protected virtual void Method1(){}
protected virtual void Method2(){}
}
public class B: A
{
public B()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class C: A
{
public C()
{ /*Something*/}
protected override void Method1(){/*some logic*/}
protected override void Method2(){/*some other logic*/}
}
public class Main
{
private A;
public Main(){/*Something*/}
private void StartB()
{
A = new B();
}
private void StartC()
{
A = new C();
}
}
Now, what happens is, after I go through a cycle in which both the methods StartB(called first) and StartC(called second) are called, when the someevent is triggered, the code tries to execute the Method in Class B(and later Class C, I hope. I could not get there since it errors out when it calls method in Class B), instead which I want it to call only the method in Class C.
I think that, since the event is subscribed at constructor, Class B methods are still getting fired since it is subscribed initially on the call of StartB.
Question:
I want only the methods of the class that is instantiated the latest should be executed.
For Example: if StartB and StartC are called in order, when someevent is triggered the Methods in Class C should only get executed. Same Vice-Versa. How to do that?
I know am doing something terribly wrong. Any help is much appreciated.
You aren't unsubscribing from the event from your first instance so it will be called. If you don't want it to be called you need to unsubscribe. You could do something like this
class A
{
private static EventHandler lastHandler;
public A()
{
//warning, not thread safe
if(lastHandler != null)
{
someotherclass.someevent -= lastHandler;
}
lastHandler = new EventHandler(HandleEvent);
someotherclass.someevent += lastHandler;
}
but it seems pretty hacky. You are probably better off implementing a method (e.g. IDisposable) to clean up your last instance before a creating a new one.
If I understand you correctly you are saying the methods on B are being called after startC is called and you don't wish this to happen?
I'm guessing your issue is that someotherclass is a static class, or an instance is somehow being shared between all the created B's and C's - in which case you need to unregister the old event handler from someotherclass.someevent when you create the new class. If you don't unregister the handler then the someotherclass object will have a reference to the B or C object that registered with it, so even though you are overwriting the reference in the main class the object is still kept alive by the reference in the event and is still being called when the event is triggered.

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