Im trying to create a Proxy Class from an interface. In the methods I just want to collect all arguments in an object array and pass on to a known method. So faar I have managed to get it working without params and with return types. As soon as I try to create my array I get "Additional information: Common Language Runtime detected an invalid program.".. Dont really know how to debug from here and the IL codes seems to be correct ( ? ).
public class Program
{
static void Main(string[] args)
{
var v = CreateProxy<IFoo>();
v.DoSomething();
}
public static void TheMethod(object[] args)
{
}
public interface IFoo
{
void DoSomething();
}
public static T CreateProxy<T>()
{
var interfaceType = typeof(T);
AssemblyName assemblyName = new AssemblyName(string.Format("tmp_{0}", interfaceType.FullName));
string moduleName = string.Format("{0}.dll", assemblyName.Name);
string ns = interfaceType.Namespace;
if (!string.IsNullOrEmpty(ns))
ns += ".";
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);
var module = assembly.DefineDynamicModule(moduleName, false);
var type = module.DefineType(String.Format("{0}Proxy_{1}", ns, interfaceType.Name), TypeAttributes.Class | TypeAttributes.AnsiClass |TypeAttributes.Sealed |TypeAttributes.NotPublic);
type.AddInterfaceImplementation(interfaceType);
//Constructor
var ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] {});
var generator = ctor.GetILGenerator();
generator.Emit(OpCodes.Ret);
//Methods
foreach (var method in interfaceType.GetMethods())
{
var args = method.GetParameters();
var methodImpl = type.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, (from arg in args select arg.ParameterType).ToArray());
generator = methodImpl.GetILGenerator();
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ldc_I4_1);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Call, typeof(Program).GetMethod(nameof(Program.TheMethod)));
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ret);
}
return (T)Activator.CreateInstance(type.CreateType());
}
}
The method im trying to Emit should look like this.
public void DoSomething()
{
object[] arr = new object[1];
Program.TheMethod(arr);
}
What am I missing here ?
You should initialize locals:
foreach (var method in interfaceType.GetMethods())
{
var args = method.GetParameters();
var methodImpl = type.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, (from arg in args select arg.ParameterType).ToArray());
generator = methodImpl.GetILGenerator();
generator.DeclareLocal(typeof(object[]));
....
....