Created
February 22, 2023 17:24
-
-
Save rootn3rd/fe9d38a41c80a6eaa35a5e0304b6f2ff to your computer and use it in GitHub Desktop.
WeakDelegate demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
namespace WeakDelegate | |
{ | |
// Containee needn't know anything about weak references, etc. | |
// It just fires its events as normal. | |
class Containee | |
{ | |
public Containee(string id) { _id = id; } | |
public event EventHandler MyEvent; | |
public void DoIt() => MyEvent?.Invoke(this, new EventArgs()); | |
public string ID => _id; | |
~Containee() | |
{ | |
Console.WriteLine(" Containee '{0}' cleaned up", ID); | |
} | |
private string _id; | |
} | |
// Container has a reference to Containee. But doesn't want to | |
// force Containee to have a strong reference to it. Uses a | |
// WeakContainer private nested class for this. | |
class Container | |
{ | |
public void Handler1(object sender, EventArgs args) | |
{ | |
Console.WriteLine(" Container.Handler1 called with Containee '{0}'",_containee == null ? "<none>" : _containee.ID); | |
} | |
public Containee Containee | |
{ | |
get | |
{ | |
return _containee; | |
} | |
set | |
{ | |
_weakContainer ??= new WeakContainer(this); | |
// unsubscribe old | |
if (_containee != null) | |
{ | |
_containee.MyEvent -= new EventHandler(_weakContainer.Handler1); | |
} | |
// subscribe new | |
_containee = value; | |
if (_containee != null) | |
{ | |
_containee.MyEvent += new EventHandler(_weakContainer.Handler1); | |
} | |
} | |
} | |
~Container() | |
{ | |
Console.WriteLine(" Container cleaned up"); | |
} | |
#region WeakContainer | |
private class WeakContainer : WeakReference | |
{ | |
public WeakContainer(Container target) : base(target) { } | |
public void Handler1(object sender, EventArgs args) | |
{ | |
Console.WriteLine(" WeakContainer.Handler1 called"); | |
if (Target is Container b) | |
{ | |
b.Handler1(sender, args); | |
} | |
else | |
{ | |
if (sender is Containee c) | |
{ | |
c.MyEvent -= new EventHandler(Handler1); | |
Console.WriteLine(" Removed WeakContainer handler"); | |
} | |
} | |
} | |
~WeakContainer() => Console.WriteLine(" WeakContainer cleaned up"); | |
} | |
#endregion | |
private Containee _containee; | |
private WeakContainer _weakContainer = null; | |
} | |
class Class1 | |
{ | |
/// <summary> | |
/// The main entry point for the application. | |
/// </summary> | |
[STAThread] | |
static void Main(string[] args) | |
{ | |
(new Class1()).Run(); | |
} | |
private Containee containee1, containee2; | |
private void InvokeMe() | |
{ | |
Console.WriteLine("Invoking"); | |
containee1?.DoIt(); | |
containee2?.DoIt(); | |
} | |
public void Run() | |
{ | |
containee1 = new Containee("FIRST"); | |
containee2 = new Containee("SECOND"); | |
Container container = new(); | |
container.Containee = containee1; | |
InvokeMe(); | |
Console.WriteLine("Switching to containee2"); | |
container.Containee = containee2; | |
InvokeMe(); | |
Console.WriteLine("Switching back to containee1"); | |
container.Containee = containee1; | |
InvokeMe(); | |
Console.WriteLine("Setting container to null and GC'ing"); | |
container = null; | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
InvokeMe(); | |
InvokeMe(); | |
Console.ReadLine(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment