Предположим, в С# у меня есть класс с произвольным количеством Actions
, который может иметь любое количество общих аргументов:
public class Container
{
public Action a;
public Action<float> b;
public Action<int, float> c;
// etc...
}
И я регистрирую некоторые отладочные лямбда-выражения для экземпляра этого класса, которые просто выводят имя поля действия:
public static void Main()
{
Container container = new Container();
container.a += () => Console.WriteLine("a was called");
container.b += (temp1) => Console.WriteLine("b was called");
container.c += (temp1, temp2) => Console.WriteLine("c was called");
container.a();
container.b(1.5f);
container.c(1, 1.5f);
}
Я хотел бы автоматизировать создание этих отладочных лямбд с использованием отражения следующим образом:
public static void Main()
{
Container container = new Container();
GenerateDebug(container);
if(container.a != null) container.a();
if(container.b != null) container.b(1.5f);
if(container.c != null) container.c(1, 1.5f);
}
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
Action callback = () => Console.WriteLine(field.Name + " was called");
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
if(actionArgTypes.Length == 0)
{
Action action = field.GetValue(c) as System.Action;
action += callback;
field.SetValue(c, action);
}
else
{
// 1. Create an Action<T1, T2, ...> object that takes the types in 'actionArgTypes' which wraps the 'callback' action
// 2. Add this new lambda to the current Action<T1, T2, ...> field
}
}
}
Я могу получить желаемый результат для действий без аргументов — приведенный выше код действительно выводит "a was called"
— но я не знаю, как это сделать для дженериков.
Я считаю, что знаю, что мне нужно делать, но не как:
- Используйте отражение, чтобы создать
Action<T1, T2, ...>
object
, используя типы вactionArgTypes
, которые обертывают вызов действияcallback
. - Добавьте этот вновь созданный объект в Общее действие, указанное в поле.
Как мне сделать это или подобное, чтобы добиться желаемого эффекта от добавления такого обратного вызова отладки?
ILGenerator
. 19.09.2018Expression.Parameter
требует двух аргументов, поэтому я исправил его, используя:var parameters = actionArgTypes.Select( argType => Expression.Parameter(argType, null) ).ToArray();
. иметь версию, которая работает еще более универсально, это здорово, так что спасибо! 19.09.2018