J'ai besoin d'une méthode qui prend une instance de MethodInfo
représentant une méthode statique non générique avec une signature arbitraire et renvoie un délégué lié à cette méthode qui pourrait être invoqué plus tard à l'aide de Delegate.DynamicInvoke
méthode. Mon premier essai naïf ressemblait à ceci:
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.
}
}
J'espérais que le MethodInfo.CreateDelegate
la méthode pourrait déterminer le type de délégué correct lui-même. Eh bien, évidemment, cela ne peut pas. Alors, comment créer une instance de System.Type
représentant un délégué avec une signature correspondant à l'instance MethodInfo
fournie?
Vous pouvez utiliser la méthode 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()));
}
}
Il y a probablement une erreur de copier-coller dans la 2e vérification de !method.IsStatic
- vous ne devez pas y utiliser ArgumentNullException
. Et c'est un bon style de fournir un nom de paramètre comme argument à ArgumentException
.
Utilisation method.IsGenericMethod
si vous souhaitez rejeter toutes les méthodes génériques et method.ContainsGenericParameters
si vous souhaitez rejeter uniquement les méthodes génériques ayant des paramètres de type non substitués.
Vous voudrez peut-être essayer 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();
}
et l'utiliser plus tard comme suit
var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");