Глядя на дизассемблированный код TypeBuilder, кажется, что невозможно, если вам нужно более одного конструктора для каждого типа:
TypeBuilder.DefineConstructor
просто вызывает DefineConstructorNoLock
, который просто проверяет параметры и увеличивает поле constructorCount:
[SecurityCritical]
private ConstructorBuilder DefineConstructorNoLock(MethodAttributes attributes, CallingConventions callingConvention, Type[] parameterTypes, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
{
this.CheckContext(parameterTypes);
this.CheckContext(requiredCustomModifiers);
this.CheckContext(optionalCustomModifiers);
this.ThrowIfCreated();
string name;
if ((attributes & MethodAttributes.Static) == MethodAttributes.PrivateScope)
{
name = ConstructorInfo.ConstructorName;
}
else
{
name = ConstructorInfo.TypeConstructorName;
}
attributes |= MethodAttributes.SpecialName;
ConstructorBuilder result = new ConstructorBuilder(name, attributes, callingConvention, parameterTypes, requiredCustomModifiers, optionalCustomModifiers, this.m_module, this);
this.m_constructorCount++;
return result;
}
Так что, если вы просто хотите определить один конструктор для каждого типа, вы можете проверить это свойство (используя отражение, так как это личное поле) и проверить его значение:
namespace ConsoleApplication7
{
static class TypeBuilderExtension
{
public static int GetConstructorCount(this TypeBuilder t)
{
FieldInfo constCountField = typeof(TypeBuilder).GetField("m_constructorCount", BindingFlags.NonPublic | BindingFlags.Instance);
return (int) constCountField.GetValue(t);
}
}
class Program
{
static void Main(string[] args)
{
AppDomain ad = AppDomain.CurrentDomain;
AssemblyBuilder ab = ad.DefineDynamicAssembly(new AssemblyName("toto.dll"), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("toto.dll");
TypeBuilder tb = mb.DefineType("mytype");
Console.WriteLine("before constructor creation : " + tb.GetConstructorCount());
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[0]);
ILGenerator ilgen = cb.GetILGenerator();
ilgen.Emit(OpCodes.Ret);
Console.WriteLine("after constructor creation : " + tb.GetConstructorCount());
tb.CreateType();
ab.Save("toto.dll");
}
}
}
который выводит:
до создания конструктора: 0
после создания конструктора: 1
Это не даст вам фактический ConstructorBuilder, но вы будете знать, что уже определили его.
Если вы действительно хотите получить constructorBuilder и не хотите создавать слишком много перегрузок (например, 1), я бы выбрал вариант 3 с методом расширения:
static class TypeBuilderExtension
{
private static Dictionary<TypeBuilder, ConstructorBuilder> _cache = new Dictionary<TypeBuilder, ConstructorBuilder>();
public static ConstructorBuilder DefineMyConstructor(this TypeBuilder tb)
{
if (!_cache.ContainsKey(tb))
{
_cache.Add(tb, tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[0]));
}
return _cache[tb];
}
}