unity - crear delegados en c#
¿Cómo crear un delegado desde un MethodInfo cuando la firma del método no puede conocerse de antemano? (2)
Necesito un método que tome una instancia de MethodInfo
represente un método estático no genérico con firma arbitraria y devuelve un delegado vinculado a ese método que luego podría invocarse mediante el método Delegate.DynamicInvoke
. Mi primer intento ingenuo se veía así:
using System;
using System.Reflection;
class Program
{
static void Main()
{
var method = CreateDelegate(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Hello world");
}
static Delegate CreateDelegate(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentNullException("method", "The provided method is not static.");
}
if (method.ContainsGenericParameters)
{
throw new ArgumentException("The provided method contains unassigned generic type parameters.");
}
return method.CreateDelegate(typeof(Delegate)); // This does not work: System.ArgumentException: Type must derive from Delegate.
}
}
MethodInfo.CreateDelegate
que el método MethodInfo.CreateDelegate
pudiera encontrar el tipo de delegado correcto. Bueno, obviamente no puede. Entonces, ¿cómo creo una instancia de System.Type
represente un delegado con una firma que coincida con la instancia de MethodInfo
proporcionada?
Es posible que desee probar System.LinQ.Expressions
...
using System.Linq.Expressions;
...
static Delegate CreateMethod(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentException("The provided method must be static.", "method");
}
if (method.IsGenericMethod)
{
throw new ArgumentException("The provided method must not be generic.", "method");
}
var parameters = method.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType, p.Name))
.ToArray();
var call = Expression.Call(null, method, parameters);
return Expression.Lambda(call, parameters).Compile();
}
y úsala luego como sigue
var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");
Puede usar el método System.Linq.Expressions.Expression.GetDelegateType :
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
class Program
{
static void Main()
{
var writeLine = CreateDelegate(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
writeLine.DynamicInvoke("Hello world");
var readLine = CreateDelegate(typeof(Console).GetMethod("ReadLine", Type.EmptyTypes));
writeLine.DynamicInvoke(readLine.DynamicInvoke());
}
static Delegate CreateDelegate(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentException("The provided method must be static.", "method");
}
if (method.IsGenericMethod)
{
throw new ArgumentException("The provided method must not be generic.", "method");
}
return method.CreateDelegate(Expression.GetDelegateType(
(from parameter in method.GetParameters() select parameter.ParameterType)
.Concat(new[] { method.ReturnType })
.ToArray()));
}
}
Probablemente haya un error de copiar y pegar en el 2do cheque para el !method.IsStatic
: no debe usar ArgumentNullException
allí. Y es un buen estilo proporcionar un nombre de parámetro como argumento para ArgumentException
.
Utilice method.IsGenericMethod
si desea rechazar todos los métodos y métodos genéricos. method.ContainsGenericParameters
genéricos si desea rechazar solo los métodos genéricos que tengan parámetros de tipo no sustituidos.