If I decompile the Test2 constructor:
public class Test2 : VarArgTest
{
public Test2() : base("foo", __arglist("one", 2))
{
}
}
public class VarArgTest
{
public VarArgTest(string test, __arglist)
{
}
}
I get this IL:
IL_0000: ldarg.0
IL_0001: ldstr "foo"
IL_0006: ldstr "one"
IL_000b: ldc.i4.2
IL_000c: call instance vararg void VarargsTest.VarArgTest::.ctor(string,
...,
string,
int32)
I'm trying to generate the same IL stream using the ILGenerator but EmitCall only takes a MethodInfo not a ConstructorInfo and the only Emit overload that takes a ConstructorInfo has no support for passing in additional parameter types.
Okay, After reading this post
I discovered an incredibly easier method of doing this: You can get a token for the constructor with optional arguments from your method builder. Why this is so unbelievably undocumented is a mystery. A similar version of the program in my previous answer is below that does the same thing but with just using this get methodtoken api. This is much easier!
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Foo"), AssemblyBuilderAccess.RunAndSave);
var mb = ab.DefineDynamicModule(ab.GetName().Name, ab.GetName().Name + ".dll", true);
var tb = mb.DefineType("Foo", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.Public, typeof(VarArgTest));
var ctor = tb.DefineConstructor(MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.HasThis, Type.EmptyTypes);
var il = ctor.GetILGenerator();
var token= mb.GetConstructorToken(typeof(VarArgTest).GetConstructors()[0], new[] { typeof(string), typeof(int) });
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, "foo");
il.Emit(OpCodes.Ldstr, "one");
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Call,token.Token);
il.Emit(OpCodes.Ret);
var v = Activator.CreateInstance(tb.CreateType());
Console.WriteLine((v as VarArgTest).CountOfArgs);