Compile string as code

Asked

Viewed 2,225 times

22

There is how I compile a string within C#?
Example: Console.WriteLine(\"Hello World\");.

Like a eval javascript?

'Cause I had a project to load a code into a text file or something.

2 answers

24


Well, it’s already possible to generate arbitrary code and run it at runtime. But not in a simple way, not in this fluid way. You already had reflection or introspection as some prefer to call in the specific case. See at the end.

.NET Compiler Platform

Have you ever heard of .NET Compiler Platform (former Roslyn)?

He is the compiler of C# 6.0 (coming along with Visual Studio 2015 and later).

The new compiler is all written in C# and brings some advantages:

  • is much easier to maintain than the previous version written in C++;
  • is open source (Apache license, very permissive, do pretty much whatever you want with it);
  • allows community participation in its development;
  • will enable language improvements more quickly and cheaply;
  • in the majority cases is faster in modern computers;
  • has an architecture called Compile As A Service;

This last one is what interests you. There is a very complete API that makes it easy to create additional tools for the language very simply and guaranteed to treat everything in the correct and most current way of the language because it is the compiler that is providing all the code analysis. Visual Studio’s own tools are now based entirely on . NET Compiler Platform. One of the tools is to convert C# p/ VB.NET code and vice versa in a practical, precise and simple way.

Another tool being developed with it is a REPL which is a very practical way of testing code, learning language resources. It shortens the time of prototypes a lot. REPL is a kind of interpreter.

Basically the same API that allows you to create REPL solves your problem.

Engine Script

using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.Scripting.CSharp;

namespace RoslynScriptingDemo {
    class Program {
        static void Main(string[] args) {
            var engine = new ScriptEngine();
            engine.Execute(@"System.Console.WriteLine(""Hello Roslyn"");");
        }
    }
}

This API allows you to create a engine of script executing arbitrary codes.

Another example a little more complex:

using System;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.Scripting.CSharp;

namespace Test.ConsoleApp {
    public class Program {
        static void Main(string[] args) {
            var engine = new ScriptEngine();

            var session = engine.CreateSession();

            session.AddReference("System");
            session.AddReference("System.Linq");

            session.Execute(@"using System;
                              var arr = new[] {1, 2, 6};
                              foreach (var i in arr) {
                                  if(i > 1) { Console.WriteLine(i); }
                              }"
                           );

            session.Execute(@"using System;
                              using System.Linq;
                              var arr = new[] {1, 2, 6};
                              var arrResult = arr.Where(x => x > 1);
                              foreach (var i in arrResult) {
                                  Console.WriteLine(i);
                              }"
                           );

            Console.ReadLine();
        }
    }
}

I imagine it shouldn’t be hard for you to load the text from the file into a string to run. But in the last CTP I saw, there was a method to run straight from a file instead of a string. But it doesn’t make much difference, it’s more of a convenience. The API is very complete and very easy. It was something like this:

scriptEngine.ExecuteFile("script.cs");

Security

Of course arbitrary codes that can be executed are dangerous. Where do these come from scripts? Who can make them available? Who can manipulate them?

Of course this system of scripts has fewer risks than the eval Javascript. It’s harder for someone to inject malicious code into a system developed by you than into a page web. But if you don’t take proper care, it happens the same way.

Anyway, when you use this type of resource you have to understand that there are risks and they need to be minimized. Extensive checks before running a file from outside need to be performed. But the most important thing is to be aware that there is a door open for malicious executions.

C# already runs on a kind of sandbox and gives certain guarantees to avoid certain security issues. But arbitrary codes can always do more than you expect.

There is another aspect that is not very safe, which is the handling of exceptions generated in the script. This needs to be well understood. But it is a subject that goes beyond your question.

Alternative

You can today use a limited and more complicated form of this through the Codedom.

I won’t go into details since I don’t know the subject very well, but basically it consists of a series of classes that allow you to assemble the execution code originating from a source code. But I already warn that the developers of . NET themselves understand that it is very complex and that the . NET Compiler Platform will trivialize the use of arbitrary code.

There is still a way to issue the CIL (Assembly) directly but not what you need.

I put in the Github for future reference.

  • 2

    God, Codedom was such a bad... bad memory. Roslyn can already be used as is... I read recently that they have already been able to build the entire Visual Studio with this project.

  • 1

    @Yes, you can use it legally experimentally with what is in Codeplex. Too bad they took the REPL that existed in the previous Ctps. But they will put it again. It’s just being totally restructured. Good developers do this :) In addition to the tool being interesting there will be the "good practices " that people love how to make an interpreter (using the script engine) correctly. I’m glad you have one more to make it clear that Codedom is only if you’re really desperate and can’t wait for Roslyn to be in production.

9

A possible solution is to use Codedom.

An example of how to use:

    public static void Main(string[] args)
    {
        var csc = new CSharpCodeProvider();
        var parameters = new CompilerParameters(new[] {"mscorlib.dll", "System.Core.dll"}, "teste.exe", true)
            {
                GenerateExecutable = true
            };
        CompilerResults compiledAssembly = csc.CompileAssemblyFromSource(parameters,
        @"
        using System;
        class Program {
          public static void Main() {
                Console.WriteLine(""Hello world."");
          }
        }");

        var errors = compiledAssembly.Errors
                                     .Cast<CompilerError>()
                                     .ToList();

        if (errors.Any())
        {
            errors.ForEach(Console.WriteLine);
            return;
        }

        Module module = compiledAssembly.CompiledAssembly.GetModules()[0];

        Type mt = null;
        if (module != null)
            mt = module.GetType("Program");

        MethodInfo methInfo = null;
        if (mt != null)
            methInfo = mt.GetMethod("Main");

        if (methInfo != null)
            Console.WriteLine(methInfo.Invoke(null, null));
    }

The code is compiled by the class CSharpCodeProvider and may subsequently be used by reflection on the Assembly generated.

You can find another example here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.