0

I'm working on a C# application where I need to execute C# code provided as a string input using Roslyn. The challenge is to execute this code and access global variables stored in a Dictionary<string, object>. The variables are dynamic, depending on the user's input.

static async Task Main(string[] args)
{
    var variables = new Dictionary<string, object>
    {
        { "x", 10 },
        { "y", 20 },
        { "message", "Hello, Roslyn!" }
    };

    string script = @"
        var result = x + y; 
        $""{message} Result: {result}"";
    ";

    // Options de script
    var options = ScriptOptions.Default.AddReferences(
        typeof(object).Assembly
    );

    var globals = new Globals { Variables = variables };

    try
    {
        var result = await CSharpScript.EvaluateAsync<string>(
            script,
            options,
            globals
        );

        Console.WriteLine(result);
        Console.ReadLine();
    }
    catch (CompilationErrorException ex)
    {
        Console.WriteLine("Erreur de compilation :");
        Console.WriteLine(string.Join(Environment.NewLine, ex.Diagnostics));
    }
    Console.ReadLine();
}

I'm passing the globals object, but I'm getting the following compilation errors:

Erreur de compilation :
(2,26): error CS0103: The name 'x' does not exist in the current context
(2,30): error CS0103: The name 'y' does not exist in the current context
(3,16): error CS0103: The name 'message' does not exist in the current context
(3,13): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

These errors indicate that the script cannot find the variables x, y, and message, even though they are in the Dictionary. How can I correctly pass these dynamic global variables to the script?

NB : the variables used in the script can be at any type, JOBJECT DataTables...

0

1 Answer 1

1

Let's break down your compilation error into two issues:

(2,26): error CS0103: The name 'x' does not exist in the current context
(2,30): error CS0103: The name 'y' does not exist in the current context
(3,16): error CS0103: The name 'message' does not exist in the current context

For these errors this is because you just defined a Dictionary named Variables in your custom Globals class. That's why when your script is being executed there are no x or y could be found as they are stored inside Variables dictionary.

To fix it you need to access them as key-value pair:

string script = @"
    var result = (int)Variables[""x""] + (int)Variables[""y""]; 
    $""{message} Result: {result}"";
";

Remember to cast it back to int otherwise it will throw as you store the values in dictionary as object:

(2,22): error CS0019: Operator '+' cannot be applied to operands of type 'object' and 'object'

Then the other issue:

(3,13): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

This is because of you just created a string literal without doing anything in your script:

$""{message} Result: {result}"";

To fix this, and I am assuming you are trying to print the result, change your script to:

Console.WriteLine($""{Variables[""message""]} Result: {result}"");

You will need to add the import to have Console.WriteLine() works:

var options = ScriptOptions.Default
.AddReferences(typeof(object).Assembly)
.AddImports("System"); // <- Here

Otherwise it will throw the following:

(3,9): error CS0103: The name 'Console' does not exist in the current context

The complete code will be as follow:

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

var variables = new Dictionary<string, object>
    {
        { "x", 10 },
        { "y", 20 },
        { "message", "Hello, Roslyn!" }
    };

string script = @"
        var result = (int)Variables[""x""] + (int)Variables[""y""]; 
        Console.WriteLine($""{Variables[""message""]} Result: {result}"");
";

// Options de script
var options = ScriptOptions.Default
.AddReferences(typeof(object).Assembly)
.AddImports("System");

var globals = new Globals() { Variables = variables };

try
{
    var result = await CSharpScript.EvaluateAsync<string>(
        script,
        options,
        globals
    );

    Console.WriteLine(result);
    Console.ReadLine();
}
catch (CompilationErrorException ex)
{
    Console.WriteLine("Erreur de compilation :");
    Console.WriteLine(string.Join(Environment.NewLine, ex.Diagnostics));
}
Console.ReadLine();


public class Globals
{
    public Dictionary<string, object> Variables { get; set; }
}

And the output when execute:

Hello, Roslyn! Result: 30

Reference: dotnet/roslyn GitHub Repository Scripting-API-Samples

EDIT:

If the value of x and y and message is fixed, you can do the following to keep user input simple:

string preprocessing = @"
    var x = (int)Variables[""x""];
    var y = (int)Variables[""y""];
";
string script = @"
    var result = x + y; 
    Console.WriteLine($""{Variables[""message""]} Result: {result}"");
";
var builder = new StringBuilder(preprocessing);
builder.Append(script);
//...
var result = await CSharpScript.EvaluateAsync<string>(
    builder.ToString(),
    options,
    globals
);
Sign up to request clarification or add additional context in comments.

2 Comments

Hey Ferry, thank you for your infos, but my main problem is how to keep our input : script, simple. For the user it should be only " x = y + 10;" as script, and the number of variables is dynamic, and i may have diffrente type of variables for exemple : "x = obj.age + 3;" obj is just an Object in our dictionary, i may have a DataRow or JObject..
Hi @Youchenn I have updated the answer, see if it works?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.