【问题标题】:C# as a scripting language in a Xamarin Forms application?C# 作为 Xamarin Forms 应用程序中的脚本语言?
【发布时间】:2019-12-25 03:03:36
【问题描述】:

我需要能够在我的 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 

有很多人试图做同样的事情并遇到问题:

  • This site 建议添加对 mscorlib 的引用,但是 没有帮助。
  • This site 没有任何建议
  • This site 没有建议
  • 什么都没有here
  • 没有人回复this one
  • 我最喜欢的是this page,其中有问题的人被告知 Roslyn 不适用于 .NET Core,这是 .NET Core 的错。

这是我现在在我的应用程序中得到的,作为执行非常简单的脚本“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);
}

【问题讨论】:

  • 请注意,Apple 明确禁止在 iOS 应用中使用动态代码
  • 我们不使用 App Store,所以我们不必担心。
  • 只是一个建议......使用更简单的 c# 脚本,直到你让它工作。一旦它工作,使用上面的脚本。像声明一个整数,分配给它。
  • 我已经编辑了我的帖子,以明确上面的代码是我在我的应用程序中拥有的,作为执行脚本“1+2”的尝试
  • 啊,我看错了。我假设你的脚本是整个 using 块。

标签: xamarin scripting roslyn


【解决方案1】:

在 Roslyn 在这里有更好的故事之前,您可以考虑使用 Mono Evaluator 在 Xamarin.Forms iOS 或 Android 应用程序中进行动态代码评估。

  1. 添加对Mono.CSharp.dll的引用
  2. 准备评估器
var cc = new CompilerContext(new CompilerSettings(), new ReportPrinter())
var evaluator = new Evaluator(cc);

// add assembly references
evaluator.ReferenceAssembly(..);
  1. 评估脚本
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 之后引入的功能是最可靠的。

【讨论】:

    猜你喜欢
    • 2013-04-13
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2016-04-15
    • 2012-09-22
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    相关资源
    最近更新 更多