如何通过Roslyn执行C#字符串代码并访问Dictionary中的全局变量?
解决Roslyn脚本访问Dictionary动态全局变量的问题
你的问题出在两个地方:一是脚本无法直接识别Dictionary中的键作为全局变量名,二是脚本最后一行的字符串插值表达式不能单独作为语句。以下是两种可行的解决方案:
方案一:使用ExpandoObject转换Dictionary
ExpandoObject允许动态添加成员,Roslyn脚本可以直接访问这些动态成员,完美匹配你的需求:
static async Task Main(string[] args) { var variables = new Dictionary<string, object> { { "x", 10 }, { "y", 20 }, { "message", "Hello, Roslyn!" } }; // 修正脚本:将单独的字符串插值改为return语句,确保返回string类型 string script = @" var result = x + y; return $""{message} Result: {result}""; "; // 添加必要的程序集引用,包括动态对象相关的System.Dynamic.Runtime var options = ScriptOptions.Default .AddReferences( typeof(object).Assembly, typeof(ExpandoObject).Assembly, typeof(System.Linq.Enumerable).Assembly ) .AddImports("System"); // 将Dictionary转换为ExpandoObject,让脚本可以直接访问变量名 dynamic globals = new ExpandoObject(); var expandoDict = (IDictionary<string, object>)globals; foreach (var kvp in variables) { expandoDict[kvp.Key] = kvp.Value; } try { var result = await CSharpScript.EvaluateAsync<string>( script, options, globals ); Console.WriteLine(result); Console.ReadLine(); } catch (CompilationErrorException ex) { Console.WriteLine("编译错误:"); Console.WriteLine(string.Join(Environment.NewLine, ex.Diagnostics)); } Console.ReadLine(); }
方案二:自定义动态Globals类
如果需要保留Dictionary的结构,可以让Globals类继承DynamicObject,实现动态成员访问:
// 自定义支持动态成员访问的Globals类 public class Globals : DynamicObject { public Dictionary<string, object> Variables { get; set; } // 重写TryGetMember,让脚本访问变量名时从Dictionary中取值 public override bool TryGetMember(GetMemberBinder binder, out object result) { return Variables.TryGetValue(binder.Name, out result); } } 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; return $""{message} Result: {result}""; "; var options = ScriptOptions.Default .AddReferences( typeof(object).Assembly, typeof(DynamicObject).Assembly ) .AddImports("System"); // 将Globals作为dynamic传入,触发动态成员访问逻辑 dynamic 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("编译错误:"); Console.WriteLine(string.Join(Environment.NewLine, ex.Diagnostics)); } Console.ReadLine(); }
关键修正点说明
- 变量访问问题:通过ExpandoObject或自定义DynamicObject实现,让脚本中的变量名直接映射到Dictionary的键,Roslyn就能识别这些变量。
- 语句错误修正:将脚本最后一行单独的
$"{message} Result: {result}";改为return $"{message} Result: {result}";,因为EvaluateAsync需要脚本返回指定类型(这里是string)的结果,单独的表达式不能作为有效语句。
内容的提问来源于stack exchange,提问作者Youchenn
相关产品推荐
相关产品推荐

