我创建了一个方法来为构造函数创建一个(打开的)委托。您可以将它与具有任意数量的参数和变量(如 ref 和 out)的任何(静态或实例)构造函数一起使用。如果您的委托返回 void,则构造类型的实例应作为第一个参数。如果委托返回要构造的类型,则会创建一个新实例。
static public T CreateDelegate<T>(this ConstructorInfo constructor)
{
// Validate if the constructor is not null.
if (constructor == null)
throw new ArgumentNullException("constructor");
// Validate if T is a delegate.
Type delegateType = typeof(T);
if (!typeof(Delegate).IsAssignableFrom(delegateType))
throw new ArgumentException("Generic argument T must be a delegate.");
// Get alle needed information.
MethodInfo invoke = delegateType.GetMethod("Invoke");
ParameterInfo[] constructorParams = constructor.GetParameters();
ParameterInfo[] delegateParams = invoke.GetParameters();
// What kind of delegate is going to be created (open, creational, static).
bool isOpen = false;
OpCode opCode = OpCodes.Newobj;
int parameterOffset = 0;
if (constructor.IsStatic) // Open delegate.
{
opCode = OpCodes.Call;
if (invoke.ReturnType != typeof(void))
throw new ArgumentException("Delegate to static constructor cannot have a return type.");
if (delegateParams.Length != 0)
throw new ArgumentException("Delegate to static constructor cannot have any parameters.");
}
else if (invoke.ReturnType == typeof(void)) // Open delegate.
{
opCode = OpCodes.Call;
isOpen = true;
parameterOffset = 1;
if ((delegateParams.Length == 0) || (delegateParams[0].ParameterType != constructor.DeclaringType))
throw new ArgumentException("An open delegate must have a first argument of the same type as the type that is being constructed.");
}
else // Creational delegate.
{
if (invoke.ReturnType != constructor.DeclaringType)
throw new ArgumentException("Return type of delegate must be equal to the type that is being constructed.");
}
// Validate the parameters (if any).
if (constructorParams.Length + parameterOffset != delegateParams.Length)
throw new ArgumentException(isOpen
? "The number of parameters of the delegate (the argument for the instance excluded) must be the same as the number of parameters of the constructor."
: "The number of parameters of the delegate must be the same as the number of parameters of the constructor.");
for (int i = 0; i < constructorParams.Length; i++)
{
ParameterInfo constructorParam = constructorParams[i];
ParameterInfo delegateParam = delegateParams[i + parameterOffset];
if (constructorParam.ParameterType != delegateParam.ParameterType)
throw new ArgumentException("Arguments of constructor and delegate do not match.");
}
// Create the dynamic method.
DynamicMethod method = new DynamicMethod(
"",
invoke.ReturnType,
delegateParams.Select(p => p.ParameterType).ToArray(),
constructor.DeclaringType.Module,
true);
// Create the IL.
ILGenerator gen = method.GetILGenerator();
for (int i = 0; i < delegateParams.Length; i++)
gen.Emit(OpCodes.Ldarg, i);
gen.Emit(opCode, constructor);
gen.Emit(OpCodes.Ret);
// Return the delegate :)
return (T)(object)method.CreateDelegate(delegateType);
}
要创建委托,请使用:
public class MyObject
{
public MyObject(int anyValue)
{
...
}
}
Action<MyObject, int> c = typeof(MyObject)
.GetConstructor(new [] { typeof(int) })
.CreateDelegate<Action<MyObject, int>>();
MyObject myObject = new MyObject(1;
c(myObject, 2);
这一切都可以通过添加一个额外的函数来缩短一点:
static public T CreateConstructorDelegate<T>(this Type type)
{
// Validate if the constructor is not null.
if (type == null)
throw new ArgumentNullException("type");
// Validate if T is a delegate.
Type delegateType = typeof(T);
if (!typeof(Delegate).IsAssignableFrom(delegateType))
throw new ArgumentException("Generic argument T must be a delegate.");
// Validate the delegate return type
MethodInfo invoke = delegateType.GetMethod("Invoke");
int parameterOffset = 0;
BindingFlags binding = BindingFlags.Public | BindingFlags.Instance;
if (invoke.ReturnType == typeof(void))
{
if (invoke.GetParameters().Length == 0)
binding = BindingFlags.NonPublic | BindingFlags.Static; // For static constructors.
else
parameterOffset = 1; // For open delegates.
}
// Validate the signatures
ParameterInfo[] delegateParams = invoke.GetParameters();
ConstructorInfo constructor = type.GetConstructor(binding, null, delegateParams.Skip(parameterOffset).Select(p => p.ParameterType).ToArray(), null);
if (constructor == null)
throw new ArgumentException("Constructor with specified parameters cannot be found.");
return constructor.CreateDelegate<T>();
}
创建委托的调用现在将是:
Action<MyObject, int> c = typeof(MyObject)
.CreateConstructorDelegate<Action<MyObject, int>>();
// Call constructor.
MyObject myObject = new MyObject(1);
// Call constructor again on same object.
c(myObject, 2);
警告! 每次调用这些方法时,都会创建一小段代码。如果您为同一个构造函数多次调用这些函数,请考虑缓存。