0
基本的には、すべての呼び出しを別のクラスにリダイレクトするラッパークラスを生成しようとしています+呼び出す前/呼び出し後にいくつかの引数/戻り値の変換を行います。しかし、il.Emit(OpCodes.Call, base_method_caller.Method)
は、エラー "System.InvalidOperationException:グローバルなメソッドまたはフィールドを別のモジュールからインポートできません"で失敗しました。デリゲートが正しいです、私はo.DynamicInvoke(...)
経由でそれを呼び出すことができます。誰もDelegateに連絡するEmitの指示書を書く方法を知っていますか?ILGeneratorを介した代理メソッドの呼び出しに失敗しました。「別のモジュールからグローバルメソッドまたはフィールドをインポートできません。
public class base_class
{
private inner_class _inner = new inner_class();
protected inner_class wrapped { get { return _inner; } }
}
public class inner_class
{
public bool do_check_value(int value) { return value > 0; }
}
[TestFixture]
public class when_wrapper_generated
{
[Test]
public void test_invoke_method_returns_expected()
{
var new_class = generate_class("test");
var wrapper = Activator.CreateInstance(new_class);
var r = wrapper.GetType().GetMethod("check_value").Invoke(wrapper, new object[]{ 10 });
Assert.That(r, Is.Not.Null);
Assert.That(r, Is.TypeOf<bool>());
}
private static Type generate_class(string new_type_name)
{
var domain = AppDomain.CurrentDomain;
var assembly_name = new AssemblyName(new_type_name + "_assembly");
var assembly = domain.DefineDynamicAssembly(assembly_name, AssemblyBuilderAccess.RunAndSave);
var module = assembly.DefineDynamicModule(new_type_name + "_module");
// type
var base_type = typeof(base_class);
var type = module.DefineType(new_type_name, TypeAttributes.Public | TypeAttributes.Class, base_type);
// method
var base_method = typeof(inner_class).GetMethod("do_check_value");
var base_method_caller = make_method_caller(typeof(base_class), base_method);
var method = type.DefineMethod("check_value", MethodAttributes.HideBySig | MethodAttributes.Public, CallingConventions.Standard,
base_method.ReturnType, base_method.GetParameters().Select(p => p.ParameterType).ToArray());
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
for (var i = 0; i < base_method.GetParameters().Length; ++i)
il.Emit(OpCodes.Ldarg_S, i + 1);
il.Emit(OpCodes.Call, base_method_caller.Method);
il.Emit(OpCodes.Ret);
var result = type.CreateType();
return result;
}
public static Delegate make_method_caller(Type base_type, MethodInfo method)
{
var thisParam = Expression.Parameter(base_type, "thisExp");
var wrapped_property = base_type.GetProperty("wrapped", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var wrapped_expr = Expression.Property(thisParam, wrapped_property);
var method_arguments = new List<ParameterExpression>();
for (var i=0; i < method.GetParameters().Length; ++i)
method_arguments.Add(Expression.Parameter(method.GetParameters()[i].ParameterType, string.Format("p{0}", i+1)));
var call_expr = Expression.Call(wrapped_expr, method, method_arguments.Cast<Expression>().ToArray());
var lambda_arguments = new List<ParameterExpression>(new[]{ thisParam });
lambda_arguments.AddRange(method_arguments);
var d = Expression.Lambda(call_expr, lambda_arguments.ToArray()).Compile();
return d;
}
}
ありがとうございました!それは今私が持っているものです。私はまた、[リフレクター用のReflectionEmitLanguageアドイン](http://reflectoraddins.codeplex.com/wikipage?title=reflectionemitlanguage)が非常に便利であることも発見しました。 –