In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly shows you the "example Analysis of .NET weak event pattern in C#", which is easy to understand and well-organized. I hope it can help you solve your doubts. Let me lead you to study and learn the article "sample Analysis of .NET weak event pattern in C#".
Introduction
You may know that event handling is a common source of memory leaks, generated by the retention of objects that are no longer in use, and you may think they should have been recycled, but they are not, and for good reason.
In this short article (hopefully), I will show this problem in the context event handling of the .net framework, and then I will teach you the standard solution to this problem, the weak event pattern. There are two ways, namely:
The "traditional" method (well, before .net 4.5, so it's not that old), it's a bit tedious to implement.
The new method provided by the .net 4.5 framework is as simple as possible
Start with the common things.
Before diving into the core of this article, let's review the two things most commonly used in code: classes and methods.
Event source
Let me introduce you to a basic but useful event source class that * reveals enough complexity to illustrate this:
Public class EventSource {public event EventHandlerEvent = delegate {}; public void Raise () {Event (this, EventArgs.Empty);}}
For those of you curious about that strange empty delegate initialization method (delegate {}), this is a technique to ensure that the event is always initialized so that you don't have to check whether it is not NULL every time you use it.
A practical method to trigger garbage collection
In. Net, garbage collection is triggered in an uncertain way. This is very disadvantageous to our experiment, which needs to track the state of the object in a certain way.
Therefore, we must periodically trigger our own garbage collection operations while avoiding copying pipeline code, which has been released in a specific method:
Static void TriggerGC () {Console.WriteLine ("Starting GC."); GC.Collect (); GC.WaitForPendingFinalizers (); GC.Collect (); Console.WriteLine ("GC finished.");}
It's not very complicated, but if you're not familiar with this pattern, you need to explain it a little bit:
* GC.Collect () triggers the .net CLR garbage collector, which is competent enough for cleaning up objects that are no longer in use, and for objects in classes that do not have finalizers (that is, destructors in c #).
GC.WaitForPendingFinalizers () waits for finalizers of other objects to execute; we need to do so, because you will see that we use finalizer methods to track when our objects are collected
The second GC.Collect () ensures that the newly generated objects are also cleaned up
Introduce a problem
First of all, let's try to understand what's wrong with event listeners through some theories and, most importantly, a demonstration.
Background
For an object to be used as an event listener, one of its instance methods needs to be registered as an event handler for another object that can produce the event (that is, the event source), which must maintain a reference to the event listener object. to call the handler of this listener when the event occurs.
This is reasonable, but if the reference is a strong reference, the listener will act as a dependency on the event source and therefore cannot be garbage collected, even if the object referencing it is the event source.
Here is a detailed illustration of what happens down here:
Event handling problem
This will not be a problem, if you can control the life cycle of listener object, you can unsubscribe from event feeds when you no longer need listener, you can often use disposable pattern (throw-after-use mode).
But if you can't validate a single point of response during the listener lifecycle, you can't dispose of it in a deterministic way, you have to rely on GC processing. This will never consider the object you prepare, as long as the event source still exists!
Examples
The theories are all good, but let's look at the problem and the real code.
This is our brave time monitor, and it's a little childish, and we soon know why:
Public class NaiveEventListener {private void OnEvent (object source, EventArgs args) {Console.WriteLine ("EventListener received event.");} public NaiveEventListener (EventSource source) {source.Event + = OnEvent;} ~ NaiveEventListener () {Console.WriteLine ("NaiveEventListener finalized.");}}
Use a simple example to see how it works:
Console.WriteLine ("= = Naive listener (bad) = ="); EventSource source = new EventSource (); NaiveEventListener listener = new NaiveEventListener (source); source.Raise (); Console.WriteLine ("Setting listener to null."); listener = null; TriggerGC (); source.Raise (); Console.WriteLine ("Setting source to null."); source = null; TriggerGC ()
Output:
EventListener received event. Setting listener to null. Starting GC. GC finished. EventListener received event. Setting source to null. Starting GC. NaiveEventListener finalized. GC finished.
Let's analyze this operation flow:
"EventListener received event.": this is the result of our call "source.Raise ()"; perfect, seems like we're listening.
"Setting listener to null.": we assign a null value to the local event listener object reference, which should allow the garbage collector to collect.
"Starting GC.": garbage collection begins.
"GC finished.": garbage collection starts, but our event listener is not reclaimed by the collector, which proves that the destructor of the event listener is not called.
"EventListener received event.": the second call to "source.Raise ()" confirms that the listener is still alive.
"Setting source to null.": we are assigning null values to the original object of the event.
"Starting GC.": second garbage collection.
"NaiveEventListener finalized.": this childish incident monitoring has finally been recalled, better late than never.
"GC finished.": the second garbage collection is complete.
Conclusion: there is indeed a hidden strong reference to the event listener to prevent it from being recycled before the event source is reclaimed!
You want a standard solution to this problem: let the event source reference the listener through weak references and recycle the listener object when the event source exists.
Here is a standard pattern and its implementation on the .NET Framework: the weak event pattern (http://msdn.microsoft.com/en-us/library/aa970850.aspx). And there is a standard pattern and its implementation in the .Net framework: the weak event pattern.
Weak event pattern
Let's see how to deal with this problem in .NET.
There is usually more than one way to do it, but in this case it can be decided directly:
If you are using .net 4.5, you will benefit from a simple implementation
In addition, you have to rely on a little artificial skill.
Traditional way
WeakEventManager is the encapsulation of all mode pipes
IWeakEventListener is a pipe that allows a component to connect to a WeakEventManager fitting
(these two are located in the WindowBase assembly, you will need to refer to your own. If you are not developing a WPF project, you should accurately refer to WindowBase.)
So there are two steps to deal with this.
First, implement a custom event manager by inheriting WeakEventManager:
Override the StartListening and StopListening methods to register a new handler and unregister an existing one, respectively; they will be used by the WeakEventManager base class.
Provides two methods to access the listener list, named "AddListener" and "RemoveListener", for consumers of custom event managers.
Provides a way to get the event manager of the current thread by exposing a static property on the custom event manager.
After that, listenr implements the IWeakEventListenr interface:
Implement the ReceiveWeakEvent method
Try to deal with this event.
If the event is handled correctly, true will be returned
There is a lot to say, but it can be converted into some code relatively:
The first is to customize the weak event manager:
Public class EventManager: WeakEventManager {private static EventManager CurrentManager {EventManager manager = (EventManager) GetCurrentManager (typeof (EventManager)); if (manager = = null) {manager = new EventManager (); SetCurrentManager (typeof (EventManager), manager);} return manager } public static void AddListener (EventSource source, IWeakEventListener listener) {CurrentManager.ProtectedAddListener (source, listener);} public static void RemoveListener (EventSource source, IWeakEventListener listener) {CurrentManager.ProtectedRemoveListener (source, listener);} protected override void StartListening (object source) {((EventSource) source). Event + = DeliverEvent } protected override void StopListening (object source) {((EventSource) source) .Event-= DeliverEvent;}}
This is followed by event listener:
Public class LegacyWeakEventListener: IWeakEventListener {private void OnEvent (object source, EventArgs args) {Console.WriteLine ("LegacyWeakEventListener received event.");} public LegacyWeakEventListener (EventSource source) {EventManager.AddListener (source, this);} public bool ReceiveWeakEvent (Type managerType, object sender, EventArgs e) {OnEvent (sender, e); return true } ~ LegacyWeakEventListener () {Console.WriteLine ("LegacyWeakEventListener finalized.");}}
Check:
Console.WriteLine ("= = Legacy weak listener (better) = ="); EventSource source = new EventSource (); LegacyWeakEventListener listener = new LegacyWeakEventListener (source); source.Raise (); Console.WriteLine ("Setting listener to null."); listener = null; TriggerGC (); source.Raise (); Console.WriteLine ("Setting source to null."); source = null; TriggerGC ()
Output:
LegacyWeakEventListener received event. Setting listener to null. Starting GC. LegacyWeakEventListener finalized. GC finished. Setting source to null. Starting GC. GC finished.
Very well, it worked, and our event listener object can now be destructed correctly in * times GC, even if the event source object is still alive and memory is no longer leaked.
But to write a bunch of code for a simple listener, imagine you have a bunch of such listener, you have to write a weak event manager for each type!
If you are good at code refactoring, you can find a smart way to ReFactor all common code.
Before the advent of .net 4.5, you had to implement the weak event manager yourself, but now that .net provides a standard solution to this problem, let's review it!
.net 4.5 mode
.net 4.5 has introduced a new generic version of the legacy WeakEventManager: WeakEventManager.
(this class can be collected in WindowsBase.)
Thanks to. Net WeakEventManager's own handling of generics, there is no need to implement new event managers one by one.
And the code is simple and readable:
Public class WeakEventListener {private void OnEvent (object source, EventArgs args) {Console.WriteLine ("WeakEventListener received event.");} public WeakEventListener (EventSource source) {WeakEventManager.AddHandler (source, "Event", OnEvent);} ~ WeakEventListener () {Console.WriteLine ("WeakEventListener finalized.");}}
A simple line of code, really concise.
The use of other implementations is similar, loading everything into the event listener class:
Console.WriteLine ("= = .net 4.5weak listener (best) = ="); EventSource source = new EventSource (); WeakEventListener listener = new WeakEventListener (source); source.Raise (); Console.WriteLine ("Setting listener to null."); listener = null; TriggerGC (); source.Raise (); Console.WriteLine ("Setting source to null."); source = null; TriggerGC ()
The output must also be correct:
WeakEventListener received event. Setting listener to null. Starting GC. WeakEventListener finalized. GC finished. Setting source to null. Starting GC. GC finished.
The expected result is the same as before, what's the problem?!
Conclusion
As you can see, implementing the weak event pattern on .net is very straightforward, especially in .net 4.5.
If you do not use .Net 4.5 to implement, you will need a lot of code, you may not use any pattern but directly use C # (+ = and-=) to see if there is a memory problem, and if you notice a leak, it will take the necessary time to implement one.
But with .net 4.5, it is free and concise, and managed by the framework, you can choose it without worry, although there is no cool C # syntax "+ =" and "- =", but the semantics are clear, which is the most important thing.
I have avoided spelling mistakes as accurately and technically as possible. If you find any typos or errors or code problems or other problems, you can comment on them.
The above is all the content of the article "sample Analysis of .NET weak event pattern in C#". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.