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[]));
....
....
Related
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);
}
}
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.
I'm trying to make this code in IL using ILGenerator.Emit
class Foo
{
...
}
public class TestClass
{
public static void test()
{
Type t = typeof(Foo);
foreach(PropertyInfo p in t.GetProperties())
{
GenerateVar(p.PropertyInfo);
}
}
public static object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
}
This is what I've done so far, and had some complications:
MethodInfo mi = TestClass.GetType().GetMethod("GenerateVar",
BindingFlags.Public |
BindingFlags.Instance);
ILGenerator generator = mb.GetILGenerator();
LocalBuilder propertyType;
LocalBuilder TestClass = mb_gen.DeclareLocal(typeof(TestClass));
foreach (PropertyInfo pi in t.GetProperties())
{
propertyType = mb_gen.DeclareLocal(pi.PropertyType);
//loads into the stack the current PropertyType and the method class
generator.Emit(OpCodes.Ldloc, TestClass);
generator.Emit(OpCodes.LdLoc, propertyType);
//calls GenerateVar(Type var) to get a PropertyType var
generator.Emit(OpCodes.Callvirt, mi);
}
It gives me the following exception:
-> expected type: System.Type , Received type: System.String
System.String is the property type that was given by: pi.PropertyType;
What am I doing wrong?
Thanks in advance
As thehennyy comment, if you can give us the full code we will can to help better. I'm trying to help here because I guess what you try to do.
So I based here on your C# code. As I understand you want to create a method that get properties of type (Foo in your case) and foreach of them, get some value based on type.
Here is a snippet of doing it for first property of the type. To complete the code you need to emit the loop, or, like you wrote in your question, loop on the properties in your C# code and emit the code for each property one after one.
static void CallGenerateVar()
{
var dm = new DynamicMethod("CallGenerateVar", typeof(object), Type.EmptyTypes, typeof(TestClass));
MethodInfo generateVarMethod = typeof(TestClass).GetMethod("GenerateVar", BindingFlags.Public | BindingFlags.Instance);
var ilGen = dm.GetILGenerator();
var properties = ilGen.DeclareLocal(typeof(PropertyInfo[]));
var index = ilGen.DeclareLocal(typeof(int));
var propInfo = ilGen.DeclareLocal(typeof(PropertyInfo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldtoken, typeof(Foo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(Type).GetMethod("GetProperties", Type.EmptyTypes));
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(PropertyInfo).GetMethod("get_PropertyType", BindingFlags.Instance | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, generateVarMethod);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ret);
var del = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
var result = del.Invoke();
}
In case our Foo type looks like this:
class Foo
{
public int MyProperty { get; set; }
}
And GenerateVar looks like this:
public object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
It will print 5
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);
I have a IEnumerable<Person> for example.
I want to be able to make it List<Person> at runtime
I have the below code but errors saying I can't convert System Runtime type
Is there something I'm missing?
private static readonly MethodInfo enumerableToListMethod = typeof(Enumerable).GetMethod("ToList", BindingFlags.Public | BindingFlags.Static);
//genericType will be Person
var genericType = modelType.GetGenericArguments().First();
var genericToListMethod = enumerableToListMethod.MakeGenericMethod(new[] { genericType });
//modelType is IEnumerable<Person>
var ienumtype = genericToListMethod.Invoke(null, new object[] { modelType });
Activator.CreateInstance(ienumtype.GetType());
You've gotta pass in the IEnumerable to the invoke, NOT the type of the enumerable - also, calling invoke will return the List, not a Type.
put in code:
var instance = < the IEnumerable >;
var modelType = instance.GetType();
//modelType is IEnumerable<Person>
var enumerableAsList = genericToListMethod.Invoke(null, new object[] { instance});
Based on your comments, I'm guessing you're after something more like this:
Func<IEnumerable<T>, List<T>> MakeMeAToListerForEnumerablesOfType<T>()
{
var itemType = typeof(T);
var enumerableToListMethod = typeof(Enumerable).GetMethod("ToList", BindingFlags.Public | BindingFlags.Static);
var genericToListMethod = enumerableToListMethod.MakeGenericMethod(new[] { itemType });
return (Func<IEnumerable<T>, List<T>>)Delegate.CreateDelegate(typeof(Func<IEnumerable<T>, List<T>>), genericToListMethod);
}
Which you would call like:
IEnumerable<string> enumerable = new string[] { "a", "b", "c" };
var toLister = MakeMeAToListerForEnumerablesOfType<string>();
Derp. Missed the call...
var enumerableAsList = toLister(enumerable);