Search code examples
c#monobootstrapping

Running a mini-program in Mono.Csharp


I'm trying to write an interactive C# teaching app, where the user can experiment/change code examples and see what happens (kinda like jsfiddle).

I've found a lot of examples for small expressions or REPL-like uses of Mono.Csharp as runtime compiler, but I can't quite find an example where a "mini program" is executed.

Here's my toy code so far (an MVC action). The "code" parameter is posted straight from a textarea.

[HttpPost]
public ActionResult Index(string code)
{
    var reportWriter = new StringWriter();
    var settings = new CompilerSettings();
    var printer = new ConsoleReportPrinter(reportWriter);
    var reports = new Report(printer);
    var eval = new Evaluator(settings, reports);

    var model = new CodeViewModel();
    model.Code = code;
    eval.Run(code);
    model.Result = reportWriter.ToString();

    return View("Index", model);
}

Now suppose the code is a string like this:

using System;
public class MyClass
{
    public void DoSomething()
    {
        Console.WriteLine("hello from DoSomething!");
    }
}

How do I bootstrap this (i.e. instantiate a MyClass object and call DoSomething on it)? I've tried just appending new MyClass().DoSomething(); to the end, but I get this:

{interactive}(1,2): warning CS0105: The using directive for `System' appeared previously in this namespace
{interactive}(1,8): (Location of the symbol related to previous warning)
{interactive}(11,1): error CS1530: Keyword `new' is not allowed on namespace elements
{interactive}(11,4): error CS1525: Unexpected symbol `MyClass', expecting `class', `delegate', `enum', `interface', `partial', or `struct'

What am I missing?


Solution

  • var reportWriter = new StringWriter();
    var settings = new CompilerSettings();
    var printer = new ConsoleReportPrinter(reportWriter);
    var reports = new Report(printer);
    var eval = new Evaluator(settings, reports);
    
    eval.Run(code);
    
    eval.Run(@"
        var output = new System.IO.StringWriter(); 
        Console.SetOut(output);
        new MyClass().DoSomething();");
    
    var model = new CodeViewModel();
    model.Code = code;
    
    if (reports.Errors > 0)
       model.Result = reportWriter.ToString();
    else
       model.Result = (string) eval.Evaluate("output.ToString();");
    
    return View("Index", model);