我需要能够在Xamarin Forms C#应用程序内执行一些小脚本,看到Microsoft.CodeAnalysis库中实现的'Roslyn'技术,我感到很兴奋。但是我无法使脚本起作用。注意,我正在尝试在应用程序中运行脚本,与Visual Studio无关。我很犹豫要生成一个外部DLL,并以某种方式从我的应用程序中调用它,但是如果需要的话,我会这样做。
我能够解析函数(使用CSharpSyntaxTree.ParseText),但是当我尝试创建最小的脚本(“ 1 + 2”)时,它每次都会引发异常:
Exception TypeInitializationException: The type initializer for 'AppContext' threw an exception.
Source: Microsoft.CodeAnalysis.Scripting
Stack trace: at Microsoft.CodeAnalysis.Scripting.Hosting.RuntimeMetadataReferenceResolver.ResolveTrustedPlatformAssemblyCore (System.String name, Microsoft.CodeAnalysis.MetadataReferenceProperties properties) [0x00007] in /_/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs:169
at Microsoft.CodeAnalysis.Scripting.Hosting.RuntimeMetadataReferenceResolver.ResolveReference (System.String reference, System.String baseFilePath, Microsoft.CodeAnalysis.MetadataReferenceProperties properties) [0x000d0] in /_/src/Scripting/Core/Hosting/Resolvers/RuntimeMetadataReferenceResolver.cs:154
at Microsoft.CodeAnalysis.Scripting.Script.GetReferencesForCompilation (Microsoft.CodeAnalysis.CommonMessageProvider messageProvider, Microsoft.CodeAnalysis.DiagnosticBag diagnostics, Microsoft.CodeAnalysis.MetadataReference languageRuntimeReferenceOpt) [0x000ac] in /_/src/Scripting/Core/Script.cs:276
at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScriptCompiler.CreateSubmission (Microsoft.CodeAnalysis.Scripting.Script script) [0x00021] in /_/src/Scripting/CSharp/CSharpScriptCompiler.cs:38
at Microsoft.CodeAnalysis.Scripting.Script.GetCompilation () [0x00008] in /_/src/Scripting/Core/Script.cs:142
at Microsoft.CodeAnalysis.Scripting.Script`1[T].GetExecutor (System.Threading.CancellationToken cancellationToken) [0x00008] in /_/src/Scripting/Core/Script.cs:359
at Microsoft.CodeAnalysis.Scripting.Script`1[T].RunAsync (System.Object globals, System.Func`2[T,TResult] catchException, System.Threading.CancellationToken cancellationToken) [0x0001b] in /_/src/Scripting/Core/Script.cs:463
at MyCompany.MyApp.AppViewModel.TryScript () [0x002d3] in C:\Workspace\Mobile\Apps\MyApp\MyApp\AppViewModel.cs:1067
Exception ArgumentNullException: Value cannot be null.
Parameter name: type
Source: mscorlib
Stack trace: at System.Reflection.IntrospectionExtensions.GetTypeInfo (System.Type type) [0x00009] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.14.0.114/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Reflection/IntrospectionExtensions.cs:14
at Microsoft.CodeAnalysis.CoreClrShim+AppContext..cctor () [0x0000f] in /_/src/Compilers/Shared/CoreClrShim.cs:28
[很多人试图做同样的事情并且遇到问题:
这是我现在在应用程序中所得到的,试图执行非常简单的脚本“ 1 + 2”:
using (var loader = new InteractiveAssemblyLoader())
{
loader.RegisterDependency(typeof(object).Assembly);
loader.RegisterDependency(typeof(AppContext).Assembly);
loader.RegisterDependency(typeof(Enumerable).Assembly);
var script = CSharpScript.Create<int>("1 + 2", assemblyLoader: loader);
var result = await script.RunAsync();
Debug.WriteLine(" Script returned " + result);
}
[直到这里有Roslyn的一个更好的故事,您可以考虑在Xamarin.Forms iOS或Android应用程序中使用Mono Evaluator进行动态代码评估。
Mono.CSharp.dll
的引用var cc = new CompilerContext(new CompilerSettings(), new ReportPrinter())
var evaluator = new Evaluator(cc);
// add assembly references
evaluator.ReferenceAssembly(..);
evaluator.Evaluate("1 + 1", out var result, out _);
Console.WriteLine(result); // 2
evaluator.Run("public class NewClass { public string HelloWorld => \"Hello World\"; }");
evaluator.Evaluate("new NewClass().HelloWorld", out result, out _);
Console.WriteLine(result); // "Hello World"
在iOS模拟器上,您需要--enable-repl
mtouch标志。在iOS设备上,您需要--interpreter
标志,并使用启用了Reflection.Emit
的Xamarin.iOS / Mono版本进行构建。我不确定当前是否在启用RefEmit的情况下发布稳定的版本,但我之前曾在here中撰写过用此版本烘烤自己的版本的信息。如果您确定动态加载外部生成的程序集就足够了,那么您可以在今天的Xamarin.iOS构建中仅使用--interpreter
标志就可以摆脱困境。
(请注意(以我的经验),评估程序支持的C#语言功能落后于Roslyn等效语言,请避免在C#6之后引入的功能最可靠。