Dynamically use the assemlby compiled runtime

I compile code dynamically from code:

string code = @" namespace CodeInjection { public static class DynConcatenateString { public static string Concatenate(string s1, string s2){ return s1 + "" ! "" + s2; } } }"; // http://stackoverflow.com/questions/604501/generating-dll-assembly-dynamically-at-run-time Console.WriteLine("Now doing some injection..."); Console.WriteLine("Creating injected code in memory"); CSharpCodeProvider codeProvider = new CSharpCodeProvider(); ICodeCompiler icc = codeProvider.CreateCompiler(); CompilerParameters parameters = new CompilerParameters(); parameters.GenerateExecutable = false; parameters.GenerateInMemory = true; //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL CompilerResults results = icc.CompileAssemblyFromSource(parameters, code); 

Then I can call the method with reflection:

  Console.WriteLine("Input two strings, and I will concate them with reflection:"); var s1 = Console.ReadLine(); var s2 = Console.ReadLine(); var result = (string)results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString").GetMethod("Concatenate").Invoke(null, new object[] { s1, s2 }); Console.WriteLine(); Console.WriteLine("Result:"); Console.WriteLine(result); 

But I would like to call something like this:

  Console.WriteLine("Input two strings, and I will concate them with dynamic type:"); var s1 = Console.ReadLine(); var s2 = Console.ReadLine(); dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString"); var resultA = (string)type.Concatenate(s1, s2); // runtime error // OR var resultB = (string)CodeInjection.DynConcatenateString.Concatenate(s1, s2); // compile error (cannot find assembly) Console.WriteLine(); Console.WriteLine("Result:"); Console.WriteLine(resultA); Console.WriteLine(resultB); 

Result B will be better. Any ideas how to do this? I need strictly .NET 4.0, we have not yet upgraded to 4.5 (because half of the team uses VS 2010). (I can refer to thoughts, I know, I'm just looking for another way, because we need to check the dyn code.)

+4
source share
4 answers

You cannot use dynamic directly in this scenario. dynamic always requires an instance of a class, but you are trying to call a method in a static class, so you do not have an instance of the class.

However, you can create a helper class and use it in combination with dynamic :

 public class StaticMethodInvoker : DynamicObject { Type _containingType; public StaticMethodInvoker(Type containingType) { _containingType = containingType; } public override bool TryInvokeMember( InvokeMemberBinder binder, Object[] args, out Object result) { result = _containingType.InvokeMember binder.Name, BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public, null, null, args); return true; } } 

Using:

 var type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString"); dynamic DynConcatenateString = new StaticMethodInvoker(type); string result = DynConcatenateString.Concatenate(s1, s2); 
+4
source

You call the static method. With dynamic you bypass the check, but you're actually trying to call Concatenate() on System.Type for CodeInjection.DynConcatenateString .

First of all, do this with the instance method:

 public class DynConcatenateString { public string Concatenate(string s1, string s2){ return s1 + "" ! "" + s2; } } 

Now let's see your code:

 dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString"); 

This is a System.Type , not an object of type CodeInjection.DynConcatenateString . If you change dynamic to var , at compile time you will see the correct type. Then you must create an instance of this type, for example:

 var type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString"); dynamic instance = Activator.CreateInstance(type); 

There is no hope for C # for syntax B, since the CodeInjection.DynConcatenateString does not exist at compile time, then this line will not be executed.

If you must keep it static, then all you can do is use reflection to invoke this method ( dynamic then useless). Don’t worry about performance ... DLR is not much faster than simple Reflection (like AFAIK, as implemented with a touch of caching).

+2
source

Why not use generic types? Define the interface of your class:

 public interface IDynConcatenateString { string Concatenate(string s1, string s2); } 

And then create dynamic code

  public T GetInstanceOf<T>(string code, string typename) { Console.WriteLine("Now doing some injection..."); Console.WriteLine("Creating injected code in memory"); CSharpCodeProvider codeProvider = new CSharpCodeProvider(); ICodeCompiler icc = codeProvider.CreateCompiler(); CompilerParameters parameters = new CompilerParameters(); parameters.GenerateExecutable = false; parameters.GenerateInMemory = true; //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL CompilerResults results = icc.CompileAssemblyFromSource(parameters, code); //type name = "CodeInjection.DynConcatenateString" T codeclass = (T)results.CompiledAssembly.CreateInstance(typename); return codeclass; } 

Try performing like this ...

 public void Exec() { string code = @" namespace CodeInjection { public class MyDynConcatenateString : IDynConcatenateString { public string Concatenate(string s1, string s2){ return s1 + "" ! "" + s2; } } }"; IDynConcatenateString writer = GetInstanceOf<IDynConcatenateString>( code, "CodeInjection.MyDynConcatenateString"); var s1 = Console.ReadLine(); var s2 = Console.ReadLine(); var result = writer.Concatenate(s1, s2); Console.WriteLine(result); } 

The implementation of IDynConcatenateString is dynamic, defined in the variable "code", as a parameter to the Exec method. You only need to define the interface, and you do not need to specify method names or class names hard.

0
source

I thought it was an interesting use, so I made a convenient version of my LateType constructor LateType(Assembly assembly, String typename) in my mobile version of the open source Dynamitey library

 dynamic DynConcatenateString = new DynamicObjects.LateType(cr.CompiledAssembly, "CodeInjection.DynConcatenateString"); Assert.That("1 ! 2", Is.EqualTo(DynConcatenateString.Concatenate("1","2"))); 
0
source

Source: https://habr.com/ru/post/1484406/


All Articles