What is Pub-Sub
Publish subscription is a design pattern that allows loose coupling between application components.
In fact, the main purpose of the subscription publishing design is a publisher-generating event channel, which is used to notify subscribers without knowing the existence of any subscribers.
Of course, the delegation of EventHandlers and Event keywords play an important role in this event handling mechanism. Let's take a look at how to use them.
Pub and Sub usage
First, let’s look at a simple subscription publishing mode.
Define an Action delegate with no return value.
namespace PubSubPattern { public class Pub { public Action OnChange { get; set; } public void Raise() { if (OnChange != null) { //Invoke OnChange Action OnChange(); } } } class Program { static void Main(string[] args) { var p = new Pub(); += () => ("Sub 1"); += () => ("Sub 2"); (); ("Press enter !"); (); } } }
As above code we create a publisher, and we call the delegate to create our anonymous method to subscribe. Since the delegate provides multicast functionality, we can use += on the OnChange property.
Although we see that the above code is executed correctly, there are still some problems in the program. If you use = instead of +=, the first subscriber will be deleted in the OnChange property.
Since OnChange is a public property, any external user of the class can make a call().
Publish Subscriptions using Event keyword
Let's take a look at the code after using the event keyword
public class Pub { public event Action OnChange = delegate { }; public void Raise() { OnChange(); } } class Program { static void Main(string[] args) { Pub p = new Pub(); += () => ("Sub 1"); += () => ("Sub 2"); (); ("Press enter !"); (); } }
Through the above code, we try to solve the problem we mentioned in the first place, we will find that usingevent
Keywords protect us onChange from unnecessary access. It does not allow the use of = that means it does not allow the allocation delegate to be made directly, so we can now avoid the use of =, thus avoiding unnecessary hassle of the application.
You may also find that OnChange is initialized as an empty delegationdelegate{}
. This ensures that our OnChange is never empty. Because when we make other calls to him, we can delete non-null checks on him in the code.
Publish Subscriptions with EventHandlers
In fact, in the subscription publishing, neither publisher nor subscriber knows each other's existence. There is oneEventHandler
, it is called a message broker or event bus, which should be known to both publishers and subscribers, and it receives all incoming messages and forwards them.
Therefore, in the following snippet, we use EventHandler instead of Action.
public delegate void EventHandler( object sender, EventArgs e )
By default, EventHandler will send objects and some event parameters as parameters.
public class MyEventArgs : EventArgs { public int Value { get; set; } public MyEventArgs(int value) { Value = value; } } public class Pub { public event EventHandler<MyEventArgs> OnChange = delegate { }; public void Raise() { OnChange(this, new MyEventArgs(1)); } } class Program { static void Main(string[] args) { Pub p = new Pub(); += (sender, e) => ("Sub :" + ); += (sender, e) => ("Sub :" + ); (); ("Press enter !"); (); } }
As in the above code, the common EventHandler is used through the pub class. It triggers the EventHandler OnChange event parameter type, which is MyArgs in the above code snippet.
Exception in event
Let's continue to talk about a situation. Let's look at the following code snippet
public class MyEventArgs : EventArgs { public int Value { get; set; } public MyEventArgs(int value) { Value = value; } } public class Pub { public event EventHandler<MyEventArgs> OnChange = delegate { }; public void Raise() { OnChange(this, new MyEventArgs(1)); } } class Program { static void Main(string[] args) { Pub p = new Pub(); += (sender, e) => ("Sub :" + ); += (sender, e) => { throw new Exception(); }; += (sender, e) => ("Sub :" + ); (); ("Press enter !"); (); } }
After running the above code, you will find that the first subscriber has successfully executed, the second subscriber has raised an exception, and the third subscriber has not been called. This is a very embarrassing thing.
If we think the above process is not what we expected, we need to manually raise the event and handle the exception, at this time we can use the defined in the Delegate base classGetInvoctionList
Come and help us achieve these.
Let's continue to read the following code
public class MyEventArgs : EventArgs { public int Value { get; set; } public MyEventArgs(int value) { Value = value; } } public class Pub { public event EventHandler<MyEventArgs> OnChange = delegate { }; public void Raise() { MyEventArgs eventArgs = new MyEventArgs(1); List<Exception> exceptions = new List<Exception>(); foreach (Delegate handler in ()) { try { (this, eventArgs); } catch (Exception e) { (e); } } if (()) { throw new AggregateException(exceptions); } } } class Program { static void Main(string[] args) { Pub p = new Pub(); += (sender, e) => ("Sub :" + ); += (sender, e) => { throw new Exception(); }; += (sender, e) => ("Sub :" + ); (); ("Press enter !"); (); } }
Reference
/hueifeng/DesignPatterns-Samples/tree/master/PubSubPattern
/observer-vs-pub-sub-pattern-50d3b27f838c
The above is a detailed content of the C# design model and the subscription publishing model. For more information about the C# subscription publishing model, please follow my other related articles!