使用外部定义类型的 CSharpScript - 无法从类型 A 转换为 A
CSharpScript Using Externally Defined Types - Can't Convert From Type A to A
问题: 无法在 CSharpScript 中使用外部定义的类型,因为我猜是由于某些程序集不匹配,它无法将对象类型从自身转换为自身。
我有 2 个项目。
普通
using System;
namespace Common
{
public class Arguments
{
public string Text;
}
public class Output
{
public bool Success;
}
}
和
CSharpScriptingExperiment
using System;
using System.Collections.Generic;
using Common;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
public class Parameters
{
public string text;
public Arguments arguments;
}
namespace CSharpScriptingExperiment
{
class Program
{
static void Main(string[] args)
{
ScriptOptions options = ScriptOptions.Default.WithImports(new List<string>() { "Common" });
options = options.AddReferences(typeof(Arguments).Assembly);
// Script will compare the text inside arguments object to the text passed in via function parameters
var script = CSharpScript.Create(@"
public class TestClass
{
public Output DoSomething(string text, Arguments args)
{
return new Output() { Success = args.Text == text };
}
}", options: options, globalsType: typeof(Parameters));
var nextStep = script.ContinueWith<object>("return new TestClass().DoSomething(text, arguments);");
// Setup the global paramters object
Parameters parameters = new Parameters();
parameters.text = "Hello";
parameters.arguments = new Arguments()
{
Text = "Hello"
};
// Run script
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Console.WriteLine(output.Success);
Console.ReadLine();
}
}
}
当我 运行 CSharpScriptingExperiment 我得到这个错误:
"(1,42): error CS1503: Argument 2: cannot convert from 'Common.Arguments [/Users/username/Projects/CSharpScriptingExperiment/CSharpScriptingExperiment/bin/Debug/netcoreapp2.2/Common.dll]' to 'Common.Arguments [Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]'"
这一行:
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Common 是一个 .NET Standard 2.0 项目。
CSharpScriptingExperiment 是一个 .NET Core 2.2 项目。
有什么想法吗?我看到其他人遇到过类似的问题,但没有找到解决方案。
通过一些小的变通方法可以正常工作。
CSharpScript 有两个不同的范围。一个是函数内部代码的正常 C# 作用域,classes 等。第二个是 CSharpScript 的独特功能,即静态作用域。它允许变量和代码是 运行 而不是在 class 或函数中——有点像 REPL。
问题是,当一个外部类型的对象被加载到静态范围内时,它又应该被传递到一个函数中,该函数接受该类型的参数,来自静态范围的对象表示和正常范围不兼容。这是导致问题的中间静态范围。
所以它是这样的:
Executing Assembly -> Script Static Scope -> Script Normal Scope
这导致了上述问题。
执行此操作时:
Executing Assembly -> Script Normal Scope
或
Script Normal Scope -> Executing Assembly
一切正常。
所以我可以 return 从函数到执行程序集的外部类型对象,但不能先通过静态范围将外部类型对象传递到函数中。
解决方法是在函数中接受一个 object
,然后在函数内部将对象转换为外部类型。
using System;
using System.Collections.Generic;
using Common;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
public class Parameters
{
public string text;
public Arguments arguments;
}
namespace CSharpScriptingExperiment
{
class Program
{
static void Main(string[] args)
{
ScriptOptions options = ScriptOptions.Default.WithImports(new List<string>() { "Common" });
options = options.AddReferences(typeof(Arguments).Assembly);
// Script will compare the text inside arguments object to the text passed in via function parameters
var script = CSharpScript.Create(@"
public class TestClass
{
public Output DoSomething(string text, object arguments)
{
Arguments args = (Arguments)arguments;
return new Output() { Success = args.Text == text };
}
}", options: options, globalsType: typeof(Parameters));
var nextStep = script.ContinueWith<object>("return new TestClass().DoSomething(text, arguments);");
// Setup the global paramters object
Parameters parameters = new Parameters();
parameters.text = "Hello";
parameters.arguments = new Arguments()
{
Text = "Hello"
};
// Run script
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Console.WriteLine(output.Success);
Console.ReadLine();
}
}
}
所以核心要点是,只要对象不通过静态范围的方式,事情就会按预期进行。如果对象需要通过静态范围,将其作为一个对象处理,并在目标函数内部强制转换为它需要的任何内容——脚本引擎似乎在执行强制转换本身时存在问题,并且类型从根本上是冲突的。
这完全基于黑盒测试和调试 - 我希望 Roslyn 团队对此进行权衡,或者希望有人参与内部工作以检查我的直觉和发现是否正确。
希望它能帮助其他遇到此问题的人!
问题: 无法在 CSharpScript 中使用外部定义的类型,因为我猜是由于某些程序集不匹配,它无法将对象类型从自身转换为自身。
我有 2 个项目。
普通
using System;
namespace Common
{
public class Arguments
{
public string Text;
}
public class Output
{
public bool Success;
}
}
和
CSharpScriptingExperiment
using System;
using System.Collections.Generic;
using Common;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
public class Parameters
{
public string text;
public Arguments arguments;
}
namespace CSharpScriptingExperiment
{
class Program
{
static void Main(string[] args)
{
ScriptOptions options = ScriptOptions.Default.WithImports(new List<string>() { "Common" });
options = options.AddReferences(typeof(Arguments).Assembly);
// Script will compare the text inside arguments object to the text passed in via function parameters
var script = CSharpScript.Create(@"
public class TestClass
{
public Output DoSomething(string text, Arguments args)
{
return new Output() { Success = args.Text == text };
}
}", options: options, globalsType: typeof(Parameters));
var nextStep = script.ContinueWith<object>("return new TestClass().DoSomething(text, arguments);");
// Setup the global paramters object
Parameters parameters = new Parameters();
parameters.text = "Hello";
parameters.arguments = new Arguments()
{
Text = "Hello"
};
// Run script
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Console.WriteLine(output.Success);
Console.ReadLine();
}
}
}
当我 运行 CSharpScriptingExperiment 我得到这个错误:
"(1,42): error CS1503: Argument 2: cannot convert from 'Common.Arguments [/Users/username/Projects/CSharpScriptingExperiment/CSharpScriptingExperiment/bin/Debug/netcoreapp2.2/Common.dll]' to 'Common.Arguments [Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]'"
这一行:
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Common 是一个 .NET Standard 2.0 项目。
CSharpScriptingExperiment 是一个 .NET Core 2.2 项目。
有什么想法吗?我看到其他人遇到过类似的问题,但没有找到解决方案。
通过一些小的变通方法可以正常工作。
CSharpScript 有两个不同的范围。一个是函数内部代码的正常 C# 作用域,classes 等。第二个是 CSharpScript 的独特功能,即静态作用域。它允许变量和代码是 运行 而不是在 class 或函数中——有点像 REPL。
问题是,当一个外部类型的对象被加载到静态范围内时,它又应该被传递到一个函数中,该函数接受该类型的参数,来自静态范围的对象表示和正常范围不兼容。这是导致问题的中间静态范围。
所以它是这样的:
Executing Assembly -> Script Static Scope -> Script Normal Scope
这导致了上述问题。
执行此操作时:
Executing Assembly -> Script Normal Scope
或
Script Normal Scope -> Executing Assembly
一切正常。
所以我可以 return 从函数到执行程序集的外部类型对象,但不能先通过静态范围将外部类型对象传递到函数中。
解决方法是在函数中接受一个 object
,然后在函数内部将对象转换为外部类型。
using System;
using System.Collections.Generic;
using Common;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
public class Parameters
{
public string text;
public Arguments arguments;
}
namespace CSharpScriptingExperiment
{
class Program
{
static void Main(string[] args)
{
ScriptOptions options = ScriptOptions.Default.WithImports(new List<string>() { "Common" });
options = options.AddReferences(typeof(Arguments).Assembly);
// Script will compare the text inside arguments object to the text passed in via function parameters
var script = CSharpScript.Create(@"
public class TestClass
{
public Output DoSomething(string text, object arguments)
{
Arguments args = (Arguments)arguments;
return new Output() { Success = args.Text == text };
}
}", options: options, globalsType: typeof(Parameters));
var nextStep = script.ContinueWith<object>("return new TestClass().DoSomething(text, arguments);");
// Setup the global paramters object
Parameters parameters = new Parameters();
parameters.text = "Hello";
parameters.arguments = new Arguments()
{
Text = "Hello"
};
// Run script
Output output = (Output)nextStep.RunAsync(globals: parameters).Result.ReturnValue;
Console.WriteLine(output.Success);
Console.ReadLine();
}
}
}
所以核心要点是,只要对象不通过静态范围的方式,事情就会按预期进行。如果对象需要通过静态范围,将其作为一个对象处理,并在目标函数内部强制转换为它需要的任何内容——脚本引擎似乎在执行强制转换本身时存在问题,并且类型从根本上是冲突的。
这完全基于黑盒测试和调试 - 我希望 Roslyn 团队对此进行权衡,或者希望有人参与内部工作以检查我的直觉和发现是否正确。
希望它能帮助其他遇到此问题的人!