I tried to generate IL for recursive method using following strategy,
Firstly I defined type using following code snippet
private void InitializeAssembly(string outputFileName)
{
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName(outputFileName);
assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Save);
moduleBuilder = assemblyBuilder.DefineDynamicModule(outputFileName, outputFileName + ".exe");
typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
methodBuilder = typeBuilder.DefineMethod("Main",
MethodAttributes.Static | MethodAttributes.Public,
typeof(void),
System.Type.EmptyTypes);
ilGen = methodBuilder.GetILGenerator();
}
Next I started to generate IL for recursive method as given below.
MethodBuilder method = typeBuilder.DefineMethod(
“MethodName”,
MethodAttributes.Static | MethodAttributes.Public,
NodeTypeToDotNetType(func.RetType),
parameters);
ILGenerator ilOfMethod = method.GetILGenerator();
method.DefineParameter();
For calling method itself inside the method body I used following construct,
ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
Finally save generated assembly using following method.
private void SaveAssembly(string outputFileName)
{
ilGen.Emit(OpCodes.Ret);
typeBuilder.CreateType();
moduleBuilder.CreateGlobalFunctions();
assemblyBuilder.SetEntryPoint(methodBuilder);
assemblyBuilder.Save(outputFileName + ".exe");
}
Unfortunately this is not working since recursive method calling construct, inside the method returns null. Issue here is that recursive call inside the method ( i.e. ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
) returns null. Since we actually create the type inside the SaveAssembly() method, this is acceptable. So my question is that: is it possible to generate IL for recursive methods using above construct? If it is not possible, Please let me know that alternative constructs for generating IL for recursive methods.
I haven't tested it, but if I remember correctly you should be able to simply use the result of DefineMethod to emit the Call instruction:
MethodBuilder method = typeBuilder.DefineMethod("MethodName", ...);
...
ILGenerator ilOfMethod = method.GetILGenerator();
...
ilOfMethod.Emit(OpCodes.Call, method);
Related
I am trying to dynamically build a type with a method that calls into an external delegate by using System.Reflection.Emit. However when I try to call this method, my program crashes with the exception in the title at the method call. Here's my code so far:
private static void TestMethodReal() => Console.Out.WriteLine("Inside TestMethod");
// In Main()
var method = typeof(Program).GetMethod(nameof(TestMethodReal), BindingFlags.Static | BindingFlags.NonPublic)!;
var builder = MyTypeBuilder.GetTypeBuilder("TestType");
var testMethod = builder.DefineMethod("TestMethod", MethodAttributes.Public, typeof(void), Type.EmptyTypes);
var generator = testMethod.GetILGenerator();
generator.EmitCall(OpCodes.Callvirt, method, null);
generator.Emit(OpCodes.Ret);
dynamic inst = Activator.CreateInstance(builder.CreateType()!)!;
inst.TestMethod(); // <--- Exception is thrown here
The MyTypeBuilder class and GetTypeBuilder method is from this answer, slightly modified to accept a parameter for the type's name.
This program is supposed to create a new dynamic class with a method called TestMethod that calls the actual TestMethodReal method, instantiate the class, and call the method.
What am I missing?
You're using the wrong dispatch mechanism!
OpCodes.Callvirt is for virtual method calls, eg. overridable instance methods, the resolution of which needs to be deferred until runtime.
For static method invocation you'll want a plain old OpCodes.Call instruction instead:
generator.EmitCall(OpCodes.Call, method, Types.EmptyTypes);
I'm currently working on an compiler in C#, where the behaviour is defined by LambdaExpressions, and then using CompileToMethod, transformed into MethodBuilders and saved to DLL. All functions are public and static.
However, I could not find a way to extract usable MethodInfo (or another method of reference) from the MethodBuilder until the behaviour is defined and declaring type is created/sealed. That means that at that until that point, it is impossible to use Expression.Call to call these functions. That makes self-recursion or mutual referencing between two functions impossible.
I ended up using Reflection to invoke the functions at runtime, but it's very suboptimal, and I'm still curious if there's a better way.
How do i ensure functions created with LambdaExpression.CompileToMethod(MethodBuilder) can self-call?
Alternatively, is there any other way to use LambdaExpressions which would allow this and support saving as a static method to a dll?
I hope this helps.
This is complete code example which produces runtime defined type with single static recursive method.
For the simplicity of the example the recursive method is infinite - at the end of the Main method the recursive method is called
static void Main(string[] args)
{
var moduleBuilder = CreateDynamicModuleBuilder();
var typeBuilder = moduleBuilder.DefineType("Person", TypeAttributes.Public | TypeAttributes.Class);
var methodBuilder = typeBuilder.DefineMethod("SayHello", MethodAttributes.Static | MethodAttributes.Public);
var methodExpression = CreateRecursiveExpression();
var lambda = Expression.Lambda(methodExpression);
lambda.CompileToMethod(methodBuilder);
var typeInfo = typeBuilder.CreateType();
var methodInfo = typeInfo.GetMethod("SayHello", BindingFlags.Public | BindingFlags.Static);
methodInfo.Invoke(null, null);
}
private static Expression CreateRecursiveExpression()
{
var methodInfo = typeof(Console).GetMethod("WriteLine", new[] { typeof(String) });
var arg = Expression.Constant("Hello");
var consoleCall = Expression.Call(methodInfo, arg);
var sayHelloActionVariable = Expression.Variable(typeof(Action), "sayHelloAction");
var block = Expression.Block(
new[] { sayHelloActionVariable },
Expression.Assign(
sayHelloActionVariable,
Expression.Lambda(
Expression.Block(
consoleCall,
Expression.Invoke(sayHelloActionVariable)
)
)
),
Expression.Invoke(sayHelloActionVariable)
);
return block;
}
private static ModuleBuilder CreateDynamicModuleBuilder()
{
var name = new AssemblyName("Example.DynamicRecursion");
var am = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
var mb = am.DefineDynamicModule(name.Name, $"{name.Name}.dll");
return mb;
}
This code will create type with the following signature
public class Person
{
public static void SayHello()
{
Action sayHelloAction;
sayHelloAction = () =>
{
Console.WriteLine("Hello");
sayHelloAction();
}
sayHelloAction();
}
}
I have an HelloWorld method with some logic in it. I have to generate many methods with different names that have same logic implemantation as HelloWorld. If HelloWorld method don't have any parameters it's easy to do. Problem starts when I have to pass some parameters to HelloWorld using DynamicMethod. Here is a pice of code to help you understand.
public string HelloWorld(string Greeting)
{
return Greeting;
}
public void MethodGenerator()
{
MethodInfo HelloWorldMethod = typeof(MyClass).GetMethod("HelloWorld");
DynamicMethod DM = new DynamicMethod("HelloWorld", typeof(string), new Type[] { typeof(MyClass) });
ILGenerator IL = DM.GetILGenerator();
IL.Emit(OpCodes.Ldarg_0);
IL.Emit(OpCodes.Call, HelloWorldMethod);
IL.Emit(OpCodes.Ret);
Func<MyClass, string> DMDelegate = (Func<MyClass, string>)DM.CreateDelegate(typeof(Func<MyClass, string>));
string Result = DMDelegate(MyObject);
}
Please help me to modify this code for my case. Thanks in advance.
P.S. I've already googled it, and didn't found anything for my case. Here are some google results that I used
Used Code example
Another example
In general I need to be able to invoke any unmanaged function from any DLL which I don't know at the compile time.
All the articles I seen (like this https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c/) suggest using delegates but I don't know at the compile time which function I gonna invoke and even which and how many parameters it requires.
Basically I have a user input like: call "Kernel32.dll" function "DeleteFile" arguments ["C:\testfile.txt"].
Could you please advice at least how to google it? The word "dynamically" doesn't help..
The task itself is a bit crazy just because actually it's a university project. Not sure it can be useful in real life..
var dll = "kernel32.dll";
var fun = "DeleteFile";
var args = new object[] { "C:\\dev\\test.txt" };
IntPtr pDll = NativeMethods.LoadLibrary(dll);
IntPtr pFun = NativeMethods.GetProcAddress(pDll, fun);
// How can I call it in a different way, without having a delegate?
Marshal.GetDelegateForFunctionPointer(pFun, typeof(?????));
I also agree with idea of Roslyn, but when I see "Dynamic" and "P/Invoke", good old System.Reflection.Emit comes to mind:
var asmName = new AssemblyName("Win32");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Win32", emitSymbolInfo: false);
var typeBuilder = modBuilder.DefineType("Win32.User32", TypeAttributes.Class | TypeAttributes.Public);
// Optional: Use if you need to set properties on DllImportAttribute
var dllImportCtor = typeof(DllImportAttribute).GetConstructor(new Type[] { typeof(string) });
var dllImportBuilder = new CustomAttributeBuilder(dllImportCtor, new object[] { "user32.dll" });
var pinvokeBuilder = typeBuilder.DefinePInvokeMethod(
name: "ShowMessageBox",
dllName: "user32.dll",
entryName: "MessageBoxW",
attributes: MethodAttributes.Static | MethodAttributes.Public,
callingConvention: CallingConventions.Standard,
returnType: typeof(int), // typeof(void) if there is no return value.
// TODO: Construct this array from user input somehow:
parameterTypes: new Type[] { typeof(IntPtr), typeof(string), typeof(string), typeof(uint) },
nativeCallConv: CallingConvention.Winapi,
nativeCharSet: CharSet.Unicode);
pinvokeBuilder.SetCustomAttribute(dllImportBuilder);
Type user32Type = typeBuilder.CreateType();
const uint MB_YESNOCANCEL = 3;
user32Type
.GetMethod("ShowMessageBox", BindingFlags.Static | BindingFlags.Public)
// TODO: User input goes here:
.Invoke(null, new object[] { IntPtr.Zero, "Message Text", "Message Caption", MB_YESNOCANCEL });
Not pretty, I know. Just my $0.02.
WARNING: If this code is going to be called multiple times in a long running application, consider creating a new AppDoman each time, and disposing it when call is done; because this is the only way to unload generated dynamic assembly.
Not sure exactly what the end goal is, but I would take a slightly different approach. In .NET compilers are a service you can use, so you can dynamically generate an assembly and then load it and use it. So your program essentially is a "generator" you translate the input into code, compile it, load it, run it. You can use roslyn for this.
I am taking in an interface, looping through the .GetEvents() return array and attempting to implement the event on my dynamic type. At the point when I try to call TypeBuilder.CreateType(), I am greeted with this lovely error:
"Application method on type from assembly is overriding a method that has been overridden."
If I comment out the typeBuilder.DefineMethodOverride calls that attempt to implement the interface methods, at the poin when I attempt to subscribe to the event I get the error:
"The method or operation is not implemented."
Here is the method I have that is attempting to add the detected event to the emitted type. Just a quick note, I have other code defining the type and adding methods implementing those on the interface and all that code works fine. I had no problems until I attempted to add events into the mix.
protected static void AddEvent(EventInfo interfaceEvent, TypeBuilder proxyBuilder)
{
// Event methods attributes
MethodAttributes eventMethodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName;
MethodImplAttributes eventMethodImpAtr = MethodImplAttributes.Managed | MethodImplAttributes.Synchronized;
string qualifiedEventName = string.Format("{0}.{1}", typeof(T).Name, interfaceEvent.Name);
string addMethodName = string.Format("add_{0}", interfaceEvent.Name);
string remMethodName = string.Format("remove_{0}", interfaceEvent.Name);
FieldBuilder eFieldBuilder = proxyBuilder.DefineField(qualifiedEventName,
interfaceEvent.EventHandlerType, FieldAttributes.Public);
EventBuilder eBuilder = proxyBuilder.DefineEvent(qualifiedEventName, EventAttributes.None, interfaceEvent.EventHandlerType);
// ADD method
MethodBuilder addMethodBuilder = proxyBuilder.DefineMethod(addMethodName,
eventMethodAttr, null, new Type[] { interfaceEvent.EventHandlerType });
addMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// We need the 'Combine' method from the Delegate type
MethodInfo combineInfo = typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) });
// Code generation
ILGenerator ilgen = addMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, combineInfo);
ilgen.Emit(OpCodes.Castclass, interfaceEvent.EventHandlerType);
ilgen.Emit(OpCodes.Stfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ret);
// REMOVE method
MethodBuilder removeMethodBuilder = proxyBuilder.DefineMethod(remMethodName,
eventMethodAttr, null, new Type[] { interfaceEvent.EventHandlerType });
removeMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
MethodInfo removeInfo = typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) });
// Code generation
ilgen = removeMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, removeInfo);
ilgen.Emit(OpCodes.Castclass, interfaceEvent.EventHandlerType);
ilgen.Emit(OpCodes.Stfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ret);
// Finally, setting the AddOn and RemoveOn methods for our event
eBuilder.SetAddOnMethod(addMethodBuilder);
eBuilder.SetRemoveOnMethod(removeMethodBuilder);
// Implement the method from the interface
proxyBuilder.DefineMethodOverride(addMethodBuilder, typeof(T).GetMethod("add_" + interfaceEvent.Name));
// Implement the method from the interface
proxyBuilder.DefineMethodOverride(removeMethodBuilder, typeof(T).GetMethod("remove_" + interfaceEvent.Name));
}
Google has been 0 help on this (searching for "is overriding a method that has been overridden" just returns a lot of Crystal Reports topics), and I have been struggling with this all morning. Any help would be greatly appreciated!
Nevermind. When i loop through the method's of the interface to implement them I am accidentally implementing the add/remove also.
fixed it with this in my loop: if(method.IsSpecialName) continue;