これは私の興味をそそったので、リフレクションを使用して、特定のインターフェイスも実装する一連のデリゲート(またはFunc
/ s)の周りにラッパーを構築するメソッドを次に示します。Action
Type GenerateInterfaceImplementator<TInterface>()
{
var interfaceType = typeof(TInterface);
var funcTypes = interfaceType.GetMethods()
.Select(GenerateFuncOrAction).ToArray();
AssemblyName aName =
new AssemblyName("Dynamic" + interfaceType.Name + "WrapperAssembly");
var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
aName,
AssemblyBuilderAccess.Run);
var modBuilder = assBuilder.DefineDynamicModule(aName.Name);
TypeBuilder typeBuilder = modBuilder.DefineType(
"Dynamic" + interfaceType.Name + "Wrapper",
TypeAttributes.Public);
// Define a constructor taking the same parameters as this method.
var ctrBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.HideBySig |
MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard,
funcTypes);
// Start building the constructor.
var ctrGenerator = ctrBuilder.GetILGenerator();
ctrGenerator.Emit(OpCodes.Ldarg_0);
ctrGenerator.Emit(
OpCodes.Call,
typeof(object).GetConstructor(Type.EmptyTypes));
// For each interface method, we add a field to hold the supplied
// delegate, code to store it in the constructor, and an
// implementation that calls the delegate.
byte methodIndex = 0;
foreach (var interfaceMethod in interfaceType.GetMethods())
{
ctrBuilder.DefineParameter(
methodIndex + 1,
ParameterAttributes.None,
"del_" + interfaceMethod.Name);
var delegateField = typeBuilder.DefineField(
"del_" + interfaceMethod.Name,
funcTypes[methodIndex],
FieldAttributes.Private);
ctrGenerator.Emit(OpCodes.Ldarg_0);
ctrGenerator.Emit(OpCodes.Ldarg_S, methodIndex + 1);
ctrGenerator.Emit(OpCodes.Stfld, delegateField);
var metBuilder = typeBuilder.DefineMethod(
interfaceMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual |
MethodAttributes.Final | MethodAttributes.HideBySig |
MethodAttributes.NewSlot,
interfaceMethod.ReturnType,
interfaceMethod.GetParameters()
.Select(p => p.ParameterType).ToArray());
var metGenerator = metBuilder.GetILGenerator();
metGenerator.Emit(OpCodes.Ldarg_0);
metGenerator.Emit(OpCodes.Ldfld, delegateField);
// Generate code to load each parameter.
byte paramIndex = 1;
foreach (var param in interfaceMethod.GetParameters())
{
metGenerator.Emit(OpCodes.Ldarg_S, paramIndex);
paramIndex++;
}
metGenerator.EmitCall(
OpCodes.Callvirt,
funcTypes[methodIndex].GetMethod("Invoke"),
null);
metGenerator.Emit(OpCodes.Ret);
methodIndex++;
}
ctrGenerator.Emit(OpCodes.Ret);
// Add interface implementation and finish creating.
typeBuilder.AddInterfaceImplementation(interfaceType);
var wrapperType = typeBuilder.CreateType();
// Return an instance using the constructor we created.
return wrapperType;
}
この関数Type GenerateFuncOrAction(MethodInfo method)
はひどいのでここには示されていません。メソッドが持つパラメーターの数と、voidを返すかどうかを切り替える必要があります。
ジェネレータは次のように呼び出されます。
public interface ITest
{
void M1();
string M2(int m2, string n2);
string P { get; set; }
}
...
var iType = GenerateInterfaceImplementator<ITest>();
var instance = (ITest)Activator.CreateInstance(iType,
new Action(() => { Console.WriteLine("M1 called"); return; }),
new Func<int, string, string>((ij, xjx) => xjx + ij.ToString()),
new Func<String>(() => "P getter called"),
new Action<string>(s => { Console.WriteLine(s); }));
instance.M1();
Console.WriteLine(instance.M2(6, "you are number "));
instance.P = "P setter called";
Console.WriteLine(instance.P);
私が実際に使用したのはこれが初めてReflection.Emit
なので、すべてのコメントを歓迎します。
問題は、インターフェースメソッドがによって提供される順序を知っている必要があるということですGetMethods
。