How to call method in DynamicMethod generated body - c#

I'm trying to create a sort of WCF communication between 2 software (To challenge myself).
What I mean by WCF is beeing able to have an interface as a contract in a Shared library. Then being able to use that contract in my two software.
I would like to use them as we do in WCf that mean as if the client was calling a simple method from the same software but in fact that use a TcpClient calling a TcpServer on the other side ....
As WCF I would like to be generic, so I dont want pre-built class that wrap my network logic for a specific contract.
As WCF I would like to be able to write a contract interface, then create a new instance of a the say "ClientBase" class, with my contract as template parameters, then use this client as a "Remote" of my other software.
As an exemple is always better here is what I would like :
In a shared project :
public interface IFooContract
{
void Add(int a, int b);
}
In the client :
class Program
{
static void Main(string[] args)
{
using (var client = new ClientFooContract())
{
var result = client.Add(5, 2);
}
}
}
class ClientFooContract : MyClientBase<IFooContract>, IFooContract, IDisposable
{
public int Add(int a, int b)
{
return Channel.Add(a, b);
}
}
class MyClientBase<T> where T : class
{
protected T Channel;
public MyClientBase()
{
Channel = /*Create Channel instance*/
}
}
My implementation is really close to th basics of WCF, but my issue is creating the Channel Instance, because of course I do not have any class that I can instantiate. I need a sort of dynamic class the implement that specific contract and for each method of this contract, handle the network logic for creating a TcpClient, connecting it to a remote server, sending data, waiting response and returning the result to the ClientFooContract.
Of course I could create a ChannelBase class that implement the contract and handle network for each of these method, but I would like to be generic as WCF, beeing able to provide any type of contract to my system.
I'm currently working with the Emit namespace trying to build dynamic class that contain method for now, here it my non finished code for creating an method :
class Program
{
static void Main(string[] args)
{
var methods = new List<Method>();
methods.Add(new Method()
{
Name = "Add",
Params = new List<MethodParam>()
{
new MethodParam()
{
Name = "a",
Type = typeof(int)
},
new MethodParam()
{
Name = "b",
Type = typeof(int)
}
},
ReturnType = typeof(int)
});
MyTypeBuilder.CompileResultType(methods);
}
}
public class Method
{
public string Name;
public List<MethodParam> Params;
public Type ReturnType;
}
public class MethodParam
{
public string Name;
public Type Type;
}
public static class MyTypeBuilder
{
public static Type CompileResultType(List<Method> methodList)
{
TypeBuilder tb = GetTypeBuilder();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
if (methodList != null)
foreach (var method in methodList)
CreateMethod(tb, method);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
//AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null,
new Type[] { typeof(IFoo) });
return tb;
}
private static void CreateMethod(TypeBuilder tb, Method method)
{
MethodBuilder methodBuilder = tb.DefineMethod(method.Name, MethodAttributes.Public, method.ReturnType, method.Params.Select(l => l.Type).ToArray());
ILGenerator il = methodBuilder.GetILGenerator();
}
}
Here is my struggle, I dont know how to add body to my dynamic method, I found on internet few exemples on how to create local variable etc etc , But actualy how can I create a TcpClient with the IL, do I need to place all of that in a separate method then call this method ? and how ?
How actualy can I make a simple call to a console.writeLine to actualy test my system ?
My issue is really the creation of the MethodBody, becauseI will have to do a lots of work here, not just declaring local variable and handle basic operations.
If there is at least a way to call an other method on an other class it will be helpfull
If you know anything, thanks for your help

After few hours testing I finally found the solution, for my method body issue.
Here it is with comment (in case someone, one day ends up in this topic).
class Program
{
static void Main(string[] args)
{
// Init List of method that I want to create
var methods = new List<Method>();
methods.Add(new Method()
{
Name = "Add",
Params = new List<MethodParam>()
{
new MethodParam()
{
Name = "a",
Type = typeof(int)
},
new MethodParam()
{
Name = "b",
Type = typeof(int)
}
},
ReturnType = typeof(int)
});
// Compile my type
var myType = MyTypeBuilder.CompileResultType(methods);
// Create instance of my type
var myObject = Activator.CreateInstance(myType) as IFooContract;
// Call Function
var result = myObject.Add(5, 2);
// Log
Console.WriteLine(result);
Console.Read();
}
}
// Used to store Method Infos
public class Method
{
public string Name;
public List<MethodParam> Params;
public Type ReturnType;
}
// Used to store Method param's Infos
public class MethodParam
{
public string Name;
public Type Type;
}
// Builder for the Dynamic class
public static class MyTypeBuilder
{
public static Type CompileResultType(List<Method> methodList)
{
TypeBuilder tb = GetTypeBuilder();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
if (methodList != null)
{
// Loop throught all method definition
foreach (var method in methodList)
{
// Generate new method on the dynamic class
CreateMethod(tb, method);
}
}
// Create the Dynamic class
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null,
new Type[] { typeof(IFooContract) }); // <= Interface that the Dynamic class will implement (used for intellisens)
tb.AddInterfaceImplementation(typeof(IFooContract)); // <= Specify that the class will implement that interface
return tb;
}
private static void CreateMethod(TypeBuilder tb, Method method)
{
// Create Method builder
MethodBuilder mb = tb.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, method.Params.Select(x => x.Type).ToArray());
// Get the IL Generator
ILGenerator il = mb.GetILGenerator();
// Start Build Method Body :
// Load first parameter on evaluation stack
il.Emit(OpCodes.Ldarg_1);
// Load Second parameter on evaluation stack
il.Emit(OpCodes.Ldarg_2);
// Use the two last element loaded as operand for "+" operation
il.Emit(OpCodes.Add);
// Push the last element on evaluation stack as return of the function
il.Emit(OpCodes.Ret);
// Stop Build Method Body
// Explicitly set this new function as the implementation of the interface function
MethodInfo interfaceMethod = typeof(IFooContract).GetMethod(method.name);
tb.DefineMethodOverride(mb, interfaceMethod);
}
}

Related

StructureMap proxy all instances or modify instances just before returning

In StructureMap we can proxy TInterface and TConcreteImpl with TProxy this this:
ConfigurationExpression config = ...
config.For<TInterface>().DecorateAllWith<TProxy>();
config.For<TInterface>().Use<TConcreteImpl>();
I wanted to use DispatchProxy (and globally log before method invocation and after invocation) and globally register it for all types being instantiated from StructureMap, I'm wondering how to accomplish this?
More specifically, I want to run the following for all the types being instantiated:
TConcreteImpl instance = ...
TInterface proxy = DispatchProxyGenerator.CreateProxyInstance(typeof (TInterface), typeof (TProxy))
.SetParameters(instance);
I already experimented with IInstancePolicy of StructureMap but no success because Instance is not the actual object instance.
public class Policy : IInstancePolicy
{
public void Apply(Type pluginType, Instance instance)
{
}
}
Thank you so much
Looks like implementing a custom IInterceptorPolicy fits here. It will be called for all types in the container, and may produce decorators for some/all of them.
An example of it with dummy logger to console:
public class CustomInterception : IInterceptorPolicy
{
public string Description => "test interception Console.WriteLine each method' arguments and return value";
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, StructureMap.Pipeline.Instance instance)
{
Type dispatchProxyType = DummyDispatchProxyDontUseAtWork.GenerateStructureMapCompatibleDispatchProxyType(pluginType);
yield return new DecoratorInterceptor(pluginType, dispatchProxyType);
}
}
Called as:
var container = new StructureMap.Container(cntnr =>
{
cntnr.Policies.Interceptors(new CustomInterception());
cntnr.For<IFoo>().Use<Foo>();
cntnr.For<IBar>().Use<Bar>();
});
var foo = container.GetInstance<IFoo>();
foo.FooFoo("1", "2");
Produced output:
FooFoo(1,2)
BarBar(2,1)
BarBar -> 21
FooFoo -> 21
The rest of example is below, so it could be executed.
Tricky thing with DispatchProxy is that it creates a new type which is hard to be constructed by StructureMap. In .Net Core 2.1 DispatchProxy makes constructor with Action... parameter, but StructureMap expects something it can create. You definitely need an alternative proxy generator which would work with StructureMap more smoothly.
public interface IBar
{
string BarBar(string a1, string a2);
}
public class Bar : IBar
{
public string BarBar(string a1, string a2) => a1 + a2;
}
public interface IFoo
{
string FooFoo(string a1, string a2);
}
public class Foo : IFoo
{
public IBar Bar { get; private set; }
public Foo(IBar bar)
{
Bar = bar;
}
public string FooFoo(string a1, string a2) => Bar.BarBar(a2, a1);
}
public class DummyDispatchProxyDontUseAtWork : DispatchProxy
{
public object Instance { get; protected set; }
public DummyDispatchProxyDontUseAtWork() : base()
{}
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Console.WriteLine($"{targetMethod.Name}({string.Join(',', args)})");
var result = targetMethod.Invoke(this.Instance, args);
Console.WriteLine($" {targetMethod.Name} -> {result}");
return result;
}
private static readonly ConcurrentDictionary<Type, Type> generatedProxyTypes = new ConcurrentDictionary<Type, Type>();
protected static readonly ConcurrentDictionary<string, object> privateHackedState = new ConcurrentDictionary<string, object>();
private static readonly AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
private static readonly ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString());
private static Type EmitDispatchProxyType(Type interfaceType)
{
object dispatchProxyObj = typeof(DispatchProxy).GetMethod("Create", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(interfaceType, typeof(DummyDispatchProxyDontUseAtWork))
.Invoke(null, null);
string typeId = "DummyDispatchProxyDontUseAtWork" + Guid.NewGuid().ToString("N");
privateHackedState[typeId] =
dispatchProxyObj.GetType().GetField("invoke", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dispatchProxyObj);
var resultTypeBuilder = moduleBuilder.DefineType(
typeId,
TypeAttributes.Public,
dispatchProxyObj.GetType());
var baseCtor = dispatchProxyObj.GetType().GetConstructors().First();
var ctor = resultTypeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
new[] {interfaceType});
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldsfld, typeof(DummyDispatchProxyDontUseAtWork).GetField(nameof(privateHackedState), BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Ldstr, typeId);
il.Emit(OpCodes.Callvirt, typeof(ConcurrentDictionary<,>).MakeGenericType(typeof(string), typeof(object)).GetMethod("get_Item"));
il.Emit(OpCodes.Call, baseCtor);
var setInstanceMethodInfo = dispatchProxyObj.GetType()
.GetMethod("set_" + nameof(Instance),BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, setInstanceMethodInfo);
il.Emit(OpCodes.Ret);
return resultTypeBuilder.CreateType();
}
public static Type GenerateStructureMapCompatibleDispatchProxyType(Type interfaceType)
{
return generatedProxyTypes.GetOrAdd(interfaceType, EmitDispatchProxyType);
}
}

How to create lambdas and add them to actions using reflection

Suppose in C# I have class that has an arbitrary number of Actions, which can have any number of generic arguments:
public class Container
{
public Action a;
public Action<float> b;
public Action<int, float> c;
// etc...
}
And I am registering some debug lambdas on an instance of this class which just print out the name of the action's field:
public static void Main()
{
Container container = new Container();
container.a += () => Console.WriteLine("a was called");
container.b += (temp1) => Console.WriteLine("b was called");
container.c += (temp1, temp2) => Console.WriteLine("c was called");
container.a();
container.b(1.5f);
container.c(1, 1.5f);
}
I would like to automate the creation of these debug lambdas using reflection, as follows:
public static void Main()
{
Container container = new Container();
GenerateDebug(container);
if(container.a != null) container.a();
if(container.b != null) container.b(1.5f);
if(container.c != null) container.c(1, 1.5f);
}
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
Action callback = () => Console.WriteLine(field.Name + " was called");
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
if(actionArgTypes.Length == 0)
{
Action action = field.GetValue(c) as System.Action;
action += callback;
field.SetValue(c, action);
}
else
{
// 1. Create an Action<T1, T2, ...> object that takes the types in 'actionArgTypes' which wraps the 'callback' action
// 2. Add this new lambda to the current Action<T1, T2, ...> field
}
}
}
I'm able to get the desired result for Actions with no arguments - the above code does indeed print out "a was called" - but I don't know how to do it for generics.
I believe I know what I need to do, just not how:
Use reflection to create an Action<T1, T2, ...> object using the types in actionArgTypes, which wraps a call to the callback action.
Add this newly created object to the Generic Action specified by the field.
How would I go about doing this, or similar that achieves the desired effect of adding such a debug callback?
Here is a rather simple implementation using Expressions, one could resort to use a ILGenerator directly, but that is not worth the hussle in this case.
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
var fieldName = field.Name;
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
// Create paramter expression for each argument
var parameters = actionArgTypes.Select(Expression.Parameter).ToArray();
// Create method call expression with a constant argument
var writeLineCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new [] {typeof(string)}), Expression.Constant(fieldName + " was called"));
// Create and compile lambda using the fields type
var lambda = Expression.Lambda(field.FieldType, writeLineCall, parameters);
var #delegate = lambda.Compile();
var action = field.GetValue(c) as Delegate;
// Combine and set delegates
action = Delegate.Combine(action, #delegate);
field.SetValue(c, action);
}
}
Here is the same function using ILGenerator, that should work with .net framework 2.0+ aswell as .net core. In a real life application there should be checks, caching and probably a whole assemblybuilder:
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
var fieldName = field.Name;
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
var dm = new DynamicMethod(fieldName, typeof(void), actionArgTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, fieldName + " was called using ilgen");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new [] {typeof(string)}));
il.Emit(OpCodes.Ret);
var #delegate = dm.CreateDelegate(field.FieldType);
var action = field.GetValue(c) as Delegate;
// Combine and set delegates
action = Delegate.Combine(action, #delegate);
field.SetValue(c, action);
}
}

Using IL Emit to generate a virtual function which returns an existed object

I want to generate a derived class of BasicModel dynamically in my C# code. And I want to override the virtual property in the derived class to return an existed object.
public class BasicModel
{
[IgnoreProperty]
public virtual CloudStorageAccount StorageAccount { get; }
}
And here is the IL part. But I constantly get null from calling that method.
var IlGen2 = newMethod2.GetILGenerator();
Func<CloudStorageAccount> getStoredObj = () => parentModel.StorageAccount;
IlGen2.Emit(OpCodes.Call, getStoredObj.GetMethodInfo());
IlGen2.Emit(OpCodes.Ldobj);
IlGen2.Emit(OpCodes.Ret);
What's the problem? Or is there a better way?
Thanks a lot.
Since the delegate is the same for all instances of the type, I would define a static field that will contain the delegate and use that:
static void Main(string[] args)
{
var parentModel = new ContainerCloudStorageAccount { StorageAccount = new CloudStorageAccount() } ;
var type = CreateType("MyOverride", () => parentModel.StorageAccount);
var value = (BasicModel)type.GetConstructors().First().Invoke(new object[0]);
Console.WriteLine(value.StorageAccount);
}
public static Type CreateType(string name, Func<CloudStorageAccount> getter)
{
AppDomain myDomain = Thread.GetDomain();
AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(new AssemblyName("dynamicTypes"), AssemblyBuilderAccess.Run);
ModuleBuilder interfaceImplementationModule = myAsmBuilder.DefineDynamicModule("overrrides");
TypeBuilder typeBuilder = interfaceImplementationModule.DefineType(name,
TypeAttributes.Public | TypeAttributes.Class,
typeof(BasicModel));
var newMethod2 = typeBuilder.DefineMethod("get_StorageAccount", MethodAttributes.Virtual | MethodAttributes.Public,
typeof(CloudStorageAccount), Type.EmptyTypes
);
typeBuilder.DefineMethodOverride(newMethod2, typeof(BasicModel).GetProperty("StorageAccount").GetGetMethod());
var fieldInfo = typeBuilder.DefineField("getter", typeof(Func<CloudStorageAccount>), FieldAttributes.Static | FieldAttributes.Public);
var IlGen2 = newMethod2.GetILGenerator();
IlGen2.Emit(OpCodes.Ldsfld, fieldInfo);
IlGen2.Emit(OpCodes.Call, typeof(Func<CloudStorageAccount>).GetMethod("Invoke"));
IlGen2.Emit(OpCodes.Ret);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
var type = typeBuilder.CreateType();
type.GetField("getter").SetValue(null, getter);
return type;
}
You original solution does not work because the delegate is more then a method, it is also a target object for that method. So if you just call the method associated with the delegate it will not have the data that you captured in the delegate.

Reflection.Emit Implement interface and create array IL

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[]));
....
....

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.
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);

Categories