Is it possible in C# to create a type at runtime that inherits from a generic class where the template parameter for the base class is the current class being constructed? This will compile fine:
// I have this class:
public class OtherClass<T>
where T : OtherClass<T>
{ }
// I want to create this at runtime:
public class MyClass : OtherClass<MyClass>
{ }
but I'm not sure how to create the MyClass
using System.Reflection.Emit.ModuleBuilder.TypeBuilder
:
AssemblyName asn = new AssemblyName("test.dll");
AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_assemblies");
ModuleBuilder = modb = asb.DefineDynamicModule("test", "test.dll");
TypeBuilder tb = modb.DefineType(
"test",
TypeAttributes.Public | TypeAttributes.Class,
typeof(MyClass)); // How to specify inheritance?
// populate properties, fields, methods, etc., emit...
tb.CreateType();
Is this possible?
Edit - Based on replies so far, I've tried this:
public class OtherClass<T>
where T : OtherClass<T>
{ }
public static void CreateSimple()
{
AssemblyName asn = new AssemblyName("test");
AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_asms");
ModuleBuilder modb = asb.DefineDynamicModule("test", "test.dll");
try
{
TypeBuilder tb = modb.DefineType(
"MyClass",
TypeAttributes.Public | TypeAttributes.Class);
Type my = tb.CreateType();
tb.SetParent(typeof(OtherClass<>).MakeGenericType(my));
my = tb.CreateType();
}
catch (Exception e)
{
throw;
}
}
but get this exception:
GenericArguments[0], 'MyClass', on 'MyProject.Factory+OtherClass`1[T]'
violates the constraint of type 'T'.
Edit : Here is my final working answer :
AssemblyName asn = new AssemblyName("test.dll");
AssemblyBuilder asb = AppDomain.CurrentDomain.DefineDynamicAssembly(
asn, AssemblyBuilderAccess.RunAndSave, @"D:\test_assemblies");
ModuleBuilder modb = asb.DefineDynamicModule("test", "test.dll");
TypeBuilder tb = modb.DefineType(
"test",
TypeAttributes.Public | TypeAttributes.Class);
// Typebuilder is a sub class of Type
tb.SetParent(typeof(OtherClass<>).MakeGenericType(tb));
var t2 = tb.CreateType();
var i = Activator.CreateInstance(t2);
The trick is to call SetParent with a parametrised generic type, the parameter is the typebuilder of the type being constructed itself.
Use the TypeBuilder.SetParent(Type parent) method.
Be careful when using it, exception throwing is deferred to CreateType
call :
If parent is null, Object is used as the base type.
In the .NET Framework versions 1.0 and 1.1, no exception is thrown if parent is an interface type, but a TypeLoadException is thrown when the CreateType method is called.
The SetParent method does not check for most invalid parent types. For example, it does not reject a parent type that has no default constructor when the current type has a default constructor, it does not reject sealed types, and it does not reject the Delegate type. In all these cases, exceptions are thrown by the CreateType method.
To build your generic type OtherClass<T>
, use the MakeGenericType method :
var genericType = typeof(OtherClass<>).MakeGenericType(typeof(MyClass));
You can set the base type afterwards.
TypeBuilder.SetParent(Type)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With