C # CompilerResults GenerateInMemory?

I ran this https://stackoverflow.com> I can find his closest thing, but not quite.

Let me explain what my final goal is before my question, I create a compiler platform that includes a web interface, because of this I want to do everything in memory (not create files), so I want to be able to compile the code, and then be able to refer to objects in the class that I just compiled for arbitrary testing. I know how this sounds unsafe, so security contributions are welcome.

My question is: how to compile a C # source into memory and instantiate this class?

I am currently at the stage where I can generate a valid .dll and import it and use it inside VisualStudio manually.

My next 2 steps:

  • load assembly automatically (this is what i ask here)
    • This would mean that I no longer need to specify the path to the dll and get the address of the private members of the class manually
  • arbitrarily refer to its members
    • This means that I can create an interface for a class without knowing its predecessors, such as how the foreach loop works with pairs of key values.

To do this completely in memory, I tried this. (source then explanation)

private object sourceToObj(string source) { string source = "..."; /*my class*/ CSharpCodeProvider pro = new CSharpCodeProvider(); CompilerParameters params = new CompilerParameters(); params.GenerateInMemory = true; params.GenerateExecutable = false; params.ReferencedAssemblies.Add("System.dll"); CompilerResults res = pro.CompileAssemblyFromSource( params, source ); Assembly DOTasm = res.CompiledAssembly; AppDomain domain = AppDomain.CreateDomain( "thisdomain" ); domain.load( DOTasm , /*???*/ ); domain.CreateInstanceAndUnwrap( DOTasm .FullName, /*???*/ ); return /*???*/; } 

Finally, as this point in the code, I hope to return some kind of object, I can name the property. Therefore, the call object obj = new sourceToObj(source).class(); or something will be possible.

Walking down this path, which may be wrong, leaves me with three unknowns.

  • What is a System.Security.Policy.Evidence assemblySecurity object.
  • What is the correct parameter for AppDomain.CreateInstanceAndUnwrap()
  • How can I return this as an object?

Of course, this method may be wrong, it is based on a link above which is close, but there is no turkey.


Edit: after more research, I wanted to include a sample source file.

 namespace testNS { public partial class i18Rule { private string i18_Name; private string i18_Value; public void setName(string s) { i18_name = s; } /* Other obvious functions */ }; }; 

I believe that I have made some progress and moved to the second sentence of my question, how to create an instance of this file.

I went ahead and used AppDomain to contain my build. I also went the way of writing to disk and read it into a byte array, as it was done in this question, I happened after Compile C # on the fly .

 /* not the final method, see Philips answer for tryLoadCompiledType which validates this works */ private void sourceToUnitTest(string source, callBack CB) { var pro = new CSharpCodeProvider(); var DOMref = AppDomain.CurrentDomain.GetAssemblies() .Where(obj => !obj.IsDynamic) .Select(obj => obj.Location) .ToArray(); var Cparams = new CompilerParameters( DOMref ); Cparams.OutputAssembly = "SOURCE.DLL"; CompilerResults res = pro.CompileAssemblyFromSource(Cparams, source); Assembly asm = res.CompiledAssembly; Type[] allTypes = res.CompiledAssembly.GetTypes(); foreach (Type t in allTypes) { TryLoadCompiledType(res, t.ToString()); Debug.WriteLine(t.ToString()); } /* I don't return I do something with each type here */ } 
+6
source share
1 answer

How to compile a C # source into memory and create an instance of this class?

I had a similar problem when I wanted to use the source code for input and compilation and execute it. This is what I came up with after reading. Is it possible to dynamically compile and execute C # code snippets? :

 public CompilerResults CompileSource(string sourceCode) { var csc = new CSharpCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } }); var referencedAssemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(a => !a.FullName.StartsWith("mscorlib", StringComparison.InvariantCultureIgnoreCase)) .Where(a => !a.IsDynamic) //necessary because a dynamic assembly will throw and exception when calling a.Location .Select(a => a.Location) .ToArray(); var parameters = new CompilerParameters( referencedAssemblies); return csc.CompileAssemblyFromSource(parameters, sourceCode); } 

Then I have a helper function:

  public static object TryLoadCompiledType(this CompilerResults compilerResults, string typeName, params object[] constructorArgs) { if (compilerResults.Errors.HasErrors) { Log.Warn("Can not TryLoadCompiledType because CompilerResults.HasErrors"); return null; } var type = compilerResults.CompiledAssembly.GetType(typeName); if (null == type) { Log.Warn("Compiled Assembly does not contain a type [" + typeName + "]"); return null; } return Activator.CreateInstance(type, constructorArgs); } 

So, to collect it

  public void Example(){ dynamic instance = CompileSource("namespace Test{public class DynamicCompile{ /*method*/}}") .TryLoadCompiledType("Test.DynamicCompile"); //can now call methods on 'instance' } 
+4
source

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


All Articles