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.
Related
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);
}
}
I have a .NET 5.0 web application that instantiates classes for each of the endpoints. Those classes instantiate child classes. Is there a more elegant or efficient way to access parent instance data from child instances besides the way I'm doing it right now?
As an example:
public class ComponentClass
{
private PageClass _page;
public ComponentClass(PageClass page)
{
_page = page;
}
public void ComponentMethod()
{
// Call the method from the parent instance
page.PageMethod();
}
}
public class PageClass
{
private ComponentClass _component;
public PageClass()
{
_component = new ComponentClass(this);
}
public async Task ProcessRequest(HttpContext context)
{
// Call the component's method
_component.ComponentMethod();
}
public void PageMethod()
{
// Do something here
}
}
Specifically, I'm trying to avoid having to pass this to every ComponentClass instance...
If you want to call a method on the parent, then you have two options. The first is to pass a reference of the parent into the child. There's no way around this, an object has no way to know in which object it is referenced from. In fact, it could be referenced by multiple parent objects.
The better solution is to use events. That way the child never knows anything about the parent(s) and can emit events that any number of components can subscribe to. See here for more details on events. For example, your component could look something like this:
public class Component
{
public event EventHandler Tick;
public void DoSomething()
{
EventHandler handler = Tick;
handler?.Invoke(this, new EventArgs());
}
}
And your PageClass:
public class PageClass
{
public Component _component { get; set; }
public void Init()
{
_component = new Component();
_component.Tick += Component_Tick;
}
public void MakeComponentTick()
{
// This method is just for testing, it's likely this would be triggered by user input
_component.DoSomething();
}
private void Component_Tick(object sender, EventArgs e)
{
Console.WriteLine("Component ticked!");
}
}
In my application I have a interface IEncoder that is having event EncoderCaller.
public interface IEncoder
{
event EncoderCaller EncoderCalled;
}
public delegate void EncoderCaller(object Source, EventArgs args);
public class Video
{
public string Title { get; set; }
}
public class VideoEventArgs : EventArgs
{
public Video xVideo { get; set; }
}
public class DetectionAction : IEncoder
{
public event EncoderCaller EncoderCalled;
public void Encode(Video video)
{
//some logic to encode video
OnVideoEncoded();
}
protected virtual void OnVideoEncoded()
{
if (EncoderCalled != null)
EncoderCalled(this, EventArgs.Empty);
}
}
public class Client1: IEncoder
{
}
I need some mechanism by which I should be able to share a contract, if that is implemented by any client then that event will trigger event in my class DetectionAction .
Can someone tell me, Am I doing right thing.
How it can be done?
If you have two classes in the same process, you could consider explicitly chain events like this:
public class Client1 : IEncoder
{
public event EncoderCaller EncoderCalled;
public Client1(IEncoder anotherEncoder)
{
// Listen to event raised on another instance and raise event on this instance.
anotherEncoder.EncoderCalled += OnAnotherEncoderCalled;
}
private void OnAnotherEncoderCalled(object source, EventArgs args)
{
if (EncoderCalled != null)
EncoderCalled(this, EventArgs.Empty);
}
}
In this case, for example, anotherEncoder is DetectionAction.
However, if you are seeking solution for sharing events between two different applications running in different processes, you might be looking at inter-process communication, like this post:
Listen for events in another application
And the above example code still works, but the IEncoder in this case is an implementation with IPC support, for example a message queue listener which raises the event on message received.
This question already has answers here:
C# Language Design: explicit interface implementation of an event
(4 answers)
Closed 5 years ago.
I am in the process of creating a system that can receive messages from a variety of different sources.
Using the interface approach, I am adding a custom event which will pass the message back to the calling application.
I've used Vistual Studio's "scaffolding" using Ctrl-. to provide the implementation for the concrete class, but its added the add and remove elements but I dont really know how to wire that bit up.
Interface class
public class MessageEventArgs : EventArgs
{
public Message { get; set; }
}
public interface MessageBroker
{
void Start();
event EventHandler<MessageEventArgs> OnMessageReceived;
}
Implementation class
public class MessageSourceA : MessageBroker
{
event EventHandler<MessageEventArgs> MessageBroker.OnMessageReceived
{
add
{
// What goes here
}
remove
{
// What goes here
}
}
void MessageBroker.Start()
{
}
}
Main Program
static void Main(string[] args)
{
MessageBroker sourceA = new MessageSourceA ();
sourceA.OnMessageReceived += sourceA_OnMessageReceived;
}
private static void sourceA_OnMessageReceived(object sender, MessageEventArgs e)
{
// Do stuff with message
}
Thanks...
You could normally implement from interface.
public class MessageSourceA : IMessageBroker
{
public void Start();
public event EventHandler<MessageEventArgs> OnMessageReceived;
}
I suggest you to rename MessageBroker to IMessageBroker as its a naming convention. Since "I" helps to differentiate between class and interface when looking at code.
If there is proper reason to implement interface explicitly you need private event handler.
private event EventHandler<MessageEventArgs> _onMessageReceived;
event EventHandler<MessageEventArgs> MessageBroker.OnMessageReceived
{
add
{
_onMessageRecieved += value;
}
remove
{
_onMessageRecieved -= value;
}
}
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
}