Sei sulla pagina 1di 4

static class FastActivator

{
public delegate object TypeActivationDelegate(object[] arguments);

private static DynamicMethod MakeCreationMethodBoxed(bool


restrictedSkipVisibility, Type returnType, params Type[] paramTypes)
{
var constructor = returnType.GetConstructor(paramTypes);

if (constructor == null)
throw new
InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Could not find
constructor matching signature {0}({1})", returnType.FullName, string.Join(",",
from argument in paramTypes

select argument.FullName)));
var constructorParams = constructor.GetParameters();
var method =
new DynamicMethod(
string.Format("{0}__{1}", constructor.DeclaringType.Name,
Guid.NewGuid().ToString().Replace("-", "")), typeof(object),
new[] { typeof(object[]) }, restrictedSkipVisibility);

ILGenerator ilGenerator = method.GetILGenerator();


ilGenerator.Emit(OpCodes.Nop);
for (int i = 0; i < constructorParams.Length; i++)
{
var paramType = constructorParams[i].ParameterType;

ilGenerator.Emit(OpCodes.Ldarg_0);
switch (i)
{
case 0:
ilGenerator.Emit(OpCodes.Ldc_I4_0);
break;

case 1:
ilGenerator.Emit(OpCodes.Ldc_I4_1);
break;

case 2:
ilGenerator.Emit(OpCodes.Ldc_I4_2);
break;

case 3:
ilGenerator.Emit(OpCodes.Ldc_I4_3);
break;

case 4:
ilGenerator.Emit(OpCodes.Ldc_I4_4);
break;

case 5:
ilGenerator.Emit(OpCodes.Ldc_I4_5);
break;

case 6:
ilGenerator.Emit(OpCodes.Ldc_I4_6);
break;

case 7:
ilGenerator.Emit(OpCodes.Ldc_I4_7);
break;

case 8:
ilGenerator.Emit(OpCodes.Ldc_I4_8);
break;

default:
ilGenerator.Emit(OpCodes.Ldc_I4_S, i);
break;
}

ilGenerator.Emit(OpCodes.Ldelem_Ref);
ilGenerator.Emit(paramType.IsValueType ? OpCodes.Unbox_Any :
OpCodes.Castclass, paramType);
}

ilGenerator.Emit(OpCodes.Newobj, constructor);
ilGenerator.Emit(OpCodes.Ret);

return method;
}
private static DynamicMethod MakeCreationMethodTypeSafe(bool
restrictedSkipVisibility, Type returnType, params Type[] paramTypes)
{
var constructor = returnType.GetConstructor(paramTypes);

if (constructor == null)
throw new
InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Could not find
constructor matching signature {0}({1})", returnType.FullName, string.Join(",",
from argument in paramTypes

select argument.FullName)));
var constructorParams = constructor.GetParameters();

var method =
new DynamicMethod(
string.Format("{0}__{1}", constructor.DeclaringType.Name,
Guid.NewGuid().ToString().Replace("-", "")), constructor.DeclaringType,
(from param in constructorParams select
param.ParameterType).ToArray(), restrictedSkipVisibility);

var ilGenerator = method.GetILGenerator();


for (int i = 0; i < constructorParams.Length; i++)
if (i < 4)
switch (i)
{
case 0:
ilGenerator.Emit(OpCodes.Ldarg_0);
break;
case 1:
ilGenerator.Emit(OpCodes.Ldarg_1);
break;
case 2:
ilGenerator.Emit(OpCodes.Ldarg_2);
break;
case 3:
ilGenerator.Emit(OpCodes.Ldarg_3);
break;
}
else
ilGenerator.Emit(OpCodes.Ldarg_S, i); // Only up to 255 args

ilGenerator.Emit(OpCodes.Newobj, constructor);
ilGenerator.Emit(OpCodes.Ret);
return method;
}

public static TypeActivationDelegate GenerateDelegate(Type returnType,


params Type[] paramTypes)
{
return GenerateDelegate(false, returnType, paramTypes);
}
public static TypeActivationDelegate GenerateDelegate(bool
restrictedSkipVisibility, Type returnType, params Type[] paramTypes)
{
var constructor = returnType.GetConstructor(paramTypes);
if (constructor == null)
throw new
InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Could not find
constructor matching signature {0}({1})",

returnType.FullName,
string.Join(",",
from param in paramTypes

select param.FullName)));

var creator = MakeCreationMethodBoxed(restrictedSkipVisibility,


returnType, paramTypes);
return
(TypeActivationDelegate)creator.CreateDelegate(typeof(TypeActivationDelegate));
}

public static T GenerateFunc<T>()


where T : class
{
return GenerateFunc<T>(false);
}
public static T GenerateFunc<T>(bool restrictedSkipVisibility)
where T : class
{
var delegateType = typeof(T);
if (!typeof(Delegate).IsAssignableFrom(delegateType))
throw new ArgumentException(string.Format("{0} is not a delegate
type", delegateType.FullName));

// Validate the delegate return type


MethodInfo delMethod = delegateType.GetMethod("Invoke");
var parameters = delMethod.GetParameters();
var returnType = delMethod.ReturnType;
if (returnType == typeof(void))
throw new InvalidOperationException("Cannot register a delegate
that doesn't return anything!");

var paramTypes = (from parameter in parameters select


parameter.ParameterType).ToArray();
var constructor = returnType.GetConstructor(paramTypes);
if (constructor == null)
throw new
InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Could not find
constructor matching signature {0}({1})",

returnType.FullName,
string.Join(",",
from param in paramTypes

select param.FullName)));

if (delMethod.ReturnType != constructor.DeclaringType)
throw new InvalidOperationException("The return type of the
delegate must match the constructors declaring type");

// Validate the signatures


ParameterInfo[] delParams = delMethod.GetParameters();
ParameterInfo[] constructorParam = constructor.GetParameters();
if (delParams.Length != constructorParam.Length)
throw new InvalidOperationException("The delegate signature does
not match that of the constructor");

var method = MakeCreationMethodTypeSafe(restrictedSkipVisibility,


returnType, paramTypes);
return method.CreateDelegate(delegateType) as T;
}
}

Potrebbero piacerti anche