Skip to content

Instantly share code, notes, and snippets.

@rootn3rd
Created February 22, 2023 17:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rootn3rd/fe9d38a41c80a6eaa35a5e0304b6f2ff to your computer and use it in GitHub Desktop.
Save rootn3rd/fe9d38a41c80a6eaa35a5e0304b6f2ff to your computer and use it in GitHub Desktop.
WeakDelegate demo
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