Eru
Eru

Reputation: 397

Reflection.Emit with generic type = type is not generic

I am using Refletion.Emit, I have an interface, an abstract class and another class. What I want to achieve is create a new class based on those two.
So here is the simple interface:

public interface IHello()
{     
    string SayHello(); 
}

This is my abstract class:

public abstract class Helloer<T> where T : IHello, new()
{
        private readonly string text;

        protected Helloer(string text)
        {
            this.text = text;                
        }

        public string DoIt()
        {
            var t = new T();
            return t.SayHello() + text;
        }
}

and the second class:

public class Howdy : IHello
{
        public string SayHello() { return "Howdy"; }
}

Now this is the full main code responsible for creating the new type HowdyHelloer:

public static void Run()
    {
        var type = CreateHelloer(typeof(Howdy));
        dynamic helloer = Activator.CreateInstance(type);
        Console.WriteLine(helloer.DoIt());
    }


    public static Type CreateHelloer(Type hello)
    {
        var assemblyBuilder = GetAssemblyBuilder("MyAssembly");
        var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
        var typeBuilder = moduleBuilder.DefineType(hello.Name + "Helloer", TypeAttributes.Public);
        var parentType = typeof(Helloer<>).MakeGenericType(hello);  

        typeBuilder.SetParent(parentType);
        Type[] types = new Type[1];
        types[0] = typeof(string);
        var parentCtorGeneric1 = typeof(Helloer<>).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);


        var parentCtor = TypeBuilder.GetConstructor(parentType, parentCtorGeneric1);
        var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { });
        var ctorIl = ctor.GetILGenerator();
        ctorIl.Emit(OpCodes.Ldstr, "Partner");
        ctorIl.Emit(OpCodes.Call, parentCtor);
        ctorIl.Emit(OpCodes.Ret);

        return typeBuilder.CreateType();
    }

    public static AssemblyBuilder GetAssemblyBuilder(string name)
    {
        var assemblyName = new AssemblyName(name);
        var domain = AppDomain.CurrentDomain;
        AssemblyBuilder c =  domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        return c;
    }

On the line:

var parentCtor = TypeBuilder.GetConstructor(parentType, parentCtorGeneric1);

I'm getting an error: " 'type' must contain a TypeBuilder as a generic argument." Can anyone help me with this please? As I'm trying to solve this for last 3 days and nothing :/ I did research and to be honest I didn't found anything specific on using Emit with generic abstract classes.

Upvotes: 2

Views: 677

Answers (1)

Grundy
Grundy

Reputation: 13381

i see in your code at least two error

first:

var parentCtor = TypeBuilder.GetConstructor(parentType, parentCtorGeneric1);

here parentType was not created with TypeBuilder, so if you want get parent constuctor just get it from parent type like

var parentCtorGeneric1 = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);

second: you wrong create consctuctor code, it should like this

var ctorIl = ctor.GetILGenerator();
ctorIl.Emit(OpCodes.Ldarg_0); // show where to load the following string
ctorIl.Emit(OpCodes.Ldstr, "Partner");
ctorIl.Emit(OpCodes.Call, parentCtorGeneric1);
ctorIl.Emit(OpCodes.Ret);

Upvotes: 3

Related Questions