Skip to content

Instantly share code, notes, and snippets.

@JohannesMP
Last active April 15, 2020 12:03
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 JohannesMP/dc6b8c1461167fa8eae3a092872b8b9a to your computer and use it in GitHub Desktop.
Save JohannesMP/dc6b8c1461167fa8eae3a092872b8b9a to your computer and use it in GitHub Desktop.
Proxying an Action<T> event as Action<object> and Action in C#
using System;
using System.Collections.Generic;
public struct EventHandlerProxy<T>
{
private struct HandlerProxy
{
public Action<T> proxy;
public int count;
}
private Dictionary<object, HandlerProxy> handlerProxies;
public Action<T> Add(object handler)
{
if(handler.GetType() == typeof(Action<T>))
{
return (Action<T>)handler;
}
if (handlerProxies == null)
{
handlerProxies = new Dictionary<object, HandlerProxy>();
}
if (handlerProxies.TryGetValue(handler, out HandlerProxy handlerProxy))
{
handlerProxy.count += 1;
handlerProxies[handler] = handlerProxy;
}
else
{
handlerProxy = new HandlerProxy() { count = 1 };
if (handler is Action<object>)
{
handlerProxy.proxy = (v) => ((Action<object>)handler).Invoke(v);
}
else if (handler is Action)
{
handlerProxy.proxy = (v) => ((Action)handler).Invoke();
}
// Handles cases where handler is Action<S> where S inherits from T
// Q: Why not just return ((Action<T>)handler?
// A: While the cast is valid and even invokable, it can't be added to an Action<T> invocation list.
else
{
handlerProxy.proxy = (v) => ((Action<T>)handler).Invoke(v);
}
handlerProxies.Add(handler, handlerProxy);
}
return handlerProxy.proxy;
}
public Action<T> Remove(object handler)
{
if (handler.GetType() == typeof(Action<T>))
{
return (Action<T>)handler;
}
if (handlerProxies == null)
{
handlerProxies = new Dictionary<object, HandlerProxy>();
}
HandlerProxy entry;
if (handlerProxies.TryGetValue(handler, out entry))
{
entry.count -= 1;
if (entry.count == 0)
{
handlerProxies.Remove(handler);
}
else
{
handlerProxies[handler] = entry;
}
}
return entry.proxy;
}
}
using System;
public class Foo<T> : IFoo<T>
{
private EventHandlerProxy<T> changeProxy;
public event Action<T> ChangeValue = delegate {};
public event Action<object> ChangeObject
{
add => ChangeValue += changeProxy.Add(value);
remove => ChangeValue -= changeProxy.Remove(value);
}
public event Action ChangeEmpty
{
add => ChangeValue += changeProxy.Add(value);
remove => ChangeValue -= changeProxy.Remove(value);
}
public void InvokeChange(T value)
{
ChangeValue.Invoke(value);
}
}
using System;
public interface IFoo<T>
{
event Action<T> ChangeValue;
event Action<object> ChangeObject;
event Action ChangeEmpty;
void InvokeChange(T value);
}
using System;
public class Program
{
public static void Main()
{
IFoo<int> test1 = new Foo<int>();
test1.ChangeEmpty += () => Console.WriteLine("0) Empty!");
test1.ChangeObject += (o) => Console.WriteLine("1) Object: {0}", o);
test1.ChangeValue += (v) => Console.WriteLine("2) Value: {0}", v);
test1.ChangeObject += (o) => Console.WriteLine("3) Object: {0}", o);
test1.ChangeEmpty += () => Console.WriteLine("4) Empty!");
test1.InvokeChange(123);
Console.WriteLine("\n--------\n");
IFoo<int> test2 = new Foo<int>();
test2.ChangeEmpty += EmptyHandler;
test2.ChangeObject += ObjectHandler;
Console.WriteLine("1) EMPTY, OBJECT");
test2.InvokeChange(1);
test2.ChangeEmpty -= EmptyHandler;
test2.ChangeValue += ValueHandler;
Console.WriteLine("2) OBJECT, VALUE");
test2.InvokeChange(2);
test2.ChangeObject -= ObjectHandler;
Console.WriteLine("3) VALUE ");
test2.InvokeChange(3);
test2.ChangeObject += ObjectHandler;
test2.ChangeEmpty += EmptyHandler;
test2.ChangeValue += ValueHandler;
Console.WriteLine("4) VALUE, OBJECT, EMPTY, VALUE");
test2.InvokeChange(4);
test2.ChangeValue -= ValueHandler;
test2.ChangeValue -= ValueHandler;
test2.ChangeEmpty -= EmptyHandler;
test2.ChangeObject -= ObjectHandler;
Console.WriteLine("5) <NONE>");
test2.InvokeChange(5);
}
static void EmptyHandler() { Console.WriteLine(" - Empty!"); }
static void ObjectHandler(object val) { Console.WriteLine(" - Object: {0}", val); }
static void ValueHandler(int val) { Console.WriteLine(" - Value: {0}", val); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment