Skip to content

Instantly share code, notes, and snippets.

@scottoffen
Created August 30, 2019 17:35
Show Gist options
  • Save scottoffen/6cc89b4b64740fa9e9f82e3112396510 to your computer and use it in GitHub Desktop.
Save scottoffen/6cc89b4b64740fa9e9f82e3112396510 to your computer and use it in GitHub Desktop.
Make delegates from methods
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
namespace DelegateTesting
{
public class Program
{
public static void Main(string[] args)
{
var myClassList = GenerateList(10);
var actions = MethodDelegateCache<MyClass>
.CandidateMethods
.Select(_ => MethodDelegateCache<MyClass>.GetDelegateForMethod(_))
.ToList();
foreach (var obj in myClassList)
{
foreach (var action in actions)
{
action(obj, 1);
}
}
var method = MethodDelegateCache<MyOtherClass>.GetDelegateForMethod("Eligible");
foreach (var name in new List<string> { "Herman", "Fausta", "Cleo" })
{
var other = new MyOtherClass(name);
method(other, 999);
}
}
public static List<MyClass> GenerateList(int count)
{
var myClassList = new List<MyClass>();
for (var i = 0; i < count; i++)
{
myClassList.Add(new MyClass { Number = i });
}
return myClassList;
}
}
public class MyClass
{
public int Number { get; set; }
public void DoSomething(int value)
{
Console.WriteLine($"{value} Do Something");
}
public void DoNothing(int value)
{
Console.WriteLine($"{value} Do Nothing");
}
public void DoSmile(int value)
{
Console.WriteLine($"{value} Do Smile");
}
public void NotMe1(int value, int other)
{
}
public void NotMe2(string value)
{
}
public int NotMe3(int value)
{
return value;
}
}
public class MyOtherClass
{
private string _name;
public MyOtherClass(string name)
{
_name = name;
}
public void Eligible(int value)
{
Console.WriteLine($"{value} {_name} Eligible");
}
}
public static class MethodDelegateCache<T>
{
private static Dictionary<string, Action<T, int>> cache = new Dictionary<string, Action<T, int>>();
private static Dictionary<string, MethodInfo> mcache = new Dictionary<string, MethodInfo>();
static MethodDelegateCache()
{
var type = typeof(T);
Console.WriteLine($"Type: {type.Name}");
var methods = typeof(T).GetMethods(BindingFlags.Public|BindingFlags.Instance)
.Where(m =>
{
if (m.IsSpecialName) return false;
var args = m.GetParameters();
var retval = m.ReturnType;
return (args.Length == 1 && args[0].ParameterType == typeof(int) && retval == typeof(void));
}).ToList();
Console.WriteLine($"Methods: {methods.Count}");
foreach (var method in methods)
{
Console.WriteLine($" └── {method.Name}");
mcache.Add(method.Name, method);
}
Console.WriteLine("Done getting methods");
}
public static Action<T, int> GetDelegateForMethod(string name)
{
if (mcache.ContainsKey(name))
{
if (!cache.ContainsKey(name))
{
var action = (Action<T, int>)Delegate.CreateDelegate(typeof(Action<T, int>), null, mcache[name]);
cache.Add(name, action);
}
return cache[name];
}
throw new NotImplementedException($"{typeof(T).Name} does not contain a valid definition for method {name}");
}
public static Action<T, int> GetDelegateForMethod(MethodInfo info)
{
return GetDelegateForMethod(info.Name);
}
public static List<MethodInfo> CandidateMethods => mcache.Values.ToList();
public static List<string> CandidateMethodNames => mcache.Keys.ToList();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment