c#动态执行脚本的3种方式详解

C#动态执行脚本的3种方式详解

在C#中动态执行脚本是一种很常见的需求,在某些场景下它可以帮助我们实现更灵活的代码设计。本文将详细讲解C#中动态执行脚本的3种方式。

1. 使用CSharpCodeProvider

CSharpCodeProvider 是 .NET Framework 类库中的一种类型,可以用来在运行时编译、执行C#代码。其主要思路是将用户提供的代码字符串编译为在内存中的程序集,并在后续操作中执行这个程序集。下面是使用这种方式动态执行脚本的示例代码:

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;

namespace ScriptingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 代码字符串,可以从数据库、文本文件、Web API 等地方获取
            string code = @"
            using System;
            public class Script
            {   
                public static void Execute()
                {
                    Console.WriteLine(""Hello Dynamic Scripting!"");
                }
            }";

            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;

            CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
            if (results.Errors.HasErrors)
            {
                Console.WriteLine(results.Errors[0]);
            }
            else
            {
                Assembly assembly = results.CompiledAssembly;
                Type type = assembly.GetType("Script");
                MethodInfo method = type.GetMethod("Execute");
                method.Invoke(null, null);
            }
        }
    }
}

在以上示例中,我们定义了一个字符串变量 code,并将其作为参数传入了 CSharpCodeProvider 的 CompileAssemblyFromSource 方法中。这个方法的作用是将 code 字符串编译为一个程序集,而 parameters 则是编译的参数配置,其中 GenerateExecutable 属性表示是否生成可执行文件,GenerateInMemory 属性表示是否将程序集加载到内存中运行。

如果编译错误,我们可以通过 CompilerResults 类型的 Errors 属性获取错误信息,否则我们可以将编译好的程序集用 Assembly 类型表示,并通过反射获取其中的类型、方法等信息进行调用。

2. 使用Roslyn

Roslyn 是一个由 Microsoft 开源的 C# 和 VB.NET 的编译器,也提供了动态编译和执行C#代码的 API。相比于 CSharpCodeProvider,它的语法分析和错误提示更加友好,使用起来也更加灵活。

下面是使用 Roslyn 动态执行脚本的示例代码:

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

namespace ScriptingExample
{
    class Program
    {
        static async System.Threading.Tasks.Task Main(string[] args)
        {
            // 代码字符串,可以从数据库、文本文件、Web API 等地方获取
            string code = @"
            public class Script
            {   
                public static void Execute()
                {
                    Console.WriteLine(""Hello Roslyn!"");
                }
            }";

            ScriptOptions options = ScriptOptions.Default;
            options = options.AddReferences(typeof(Console).Assembly);
            options = options.AddReferences(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly);
            options = options.WithImports("System");

            Script script = CSharpScript.Create(code, options, typeof(ScriptHost));
            Compilation compilation = script.GetCompilation();
            if (compilation.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error))
            {
                Console.WriteLine(compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error));
                return;
            }

            ScriptState state = await script.RunAsync(new ScriptHost());
        }
    }

    public class ScriptHost
    {
    }
}

在以上示例中,我们使用了 CSharpScript.Create 方法将代码字符串编译为一个脚本。使用 Roslyn 的时候需要注意,如果要使用大部分的命名空间和类型,需要在 ScriptOptions 对象中配置正确的引用和导入语句,否则会出现编译错误。在编译通过后,我们可以通过 script.RunAsync 方法运行这段脚本,同时可以配置好 ScriptHost 类型,为脚本提供必要的环境。

3. 使用动态编译器

除了 CSharpCodeProvider 和 Roslyn 外,还有一些动态编译器可以用来动态执行脚本,如 Mono.CSharp.Compiler 和 CodeDom.Compiler.CodeCompiler。

在这里着重介绍了一下 Mono.CSharp.Compiler 的使用,在此不再赘述其他动态编译器的使用方法,感兴趣的读者可以查阅相关文档。

using System;
using System.IO;
using System.Text;
using Mono.CSharp;

namespace ScriptingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 代码字符串,可以从数据库、文本文件、Web API 等地方获取
            string code = @"
            using System;
            public class Script
            {   
                public static void Execute()
                {
                    Console.WriteLine(""Hello Mono.CSharp.Compiler!"");
                }
            }";

            Evaluator.Init(new string[0]);
            Evaluator.Evaluate(new MemoryStream(Encoding.UTF8.GetBytes(code)));
        }
    }
}

在上述 Mono.CSharp.Compiler 的示例中,我们首先使用 Evaluator.Init 初始化编译器,然后使用 Evaluator.Evaluate 执行代码字符串,这两个方法的作用和 CSharpCodeProvider 的 CompileAssemblyFromSource 相似,用于将代码字符串编译并执行。需要注意的是,Mono.CSharp.Compiler 在某些状况下会出现兼容性问题,应该根据实际需求进行选择。

总结

以上就是在C#中动态执行脚本的3种方式,每种方式都有各自的特点和优缺点,使用时应根据实际需求综合选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c#动态执行脚本的3种方式详解 - Python技术站

(1)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • ASP.NET中常用的三十三种代码第1/7页

    “ASP.NET中常用的三十三种代码”是一篇介绍常用代码的文章,通过对这些代码的学习和使用,可以提高 ASP.NET 的应用开发水平。下面是第 1/7 页的完整攻略: ASP.NET中常用的三十三种代码 – 第 1/7 页 1. 添加一个控件并指定 ID 在 ASP.NET 中,我们可以通过代码来添加一个控件并指定它的 ID。在页面的代码中,可以使用 Pag…

    C# 2023年5月31日
    00
  • C# 通过反射获取类型的字段值及给字段赋值的操作

    C#通过反射获取类型的字段值及给字段赋值的操作,可以通过以下步骤进行: 1. 获取类型对象 获取类型对象可以通过两种方式进行,一种是通过已知对象获取,另一种是通过类型名称字符串获取。以下是两种方式的示例代码: 通过已知对象获取 MyClass obj = new MyClass(); Type type = obj.GetType(); 通过类型名称字符串获…

    C# 2023年5月15日
    00
  • .net core中Grpc使用报错:The remote certificate is invalid according to the validation procedure.

    因为Grpc采用HTTP/2作为通信协议,默认采用LTS/SSL加密方式传输,比如使用.net core启动一个服务端(被调用方)时:   public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWe…

    C# 2023年4月17日
    00
  • 关于System.Convert的那些事儿

    关于System.Convert的详细讲解 System.Convert是什么? System.Convert是.NET Framework中提供的一组类型转换方法,可以将一种类型的值转换成另一种类型。它的主要作用是方便开发者进行各种类型之间的转换,使得开发过程中的数据处理更加方便、快捷、高效。 怎样使用System.Convert? System.Conv…

    C# 2023年5月15日
    00
  • Asp.net 下载功能的解决方案

    下面详细为大家介绍“Asp.net 下载功能的解决方案”的攻略。 一、方案介绍 在 Asp.net 中,我们经常需要实现文件下载的功能,这就需要对下载的过程进行控制和管理,以保证下载的正确性和安全性。为了满足这个需求,我们可以通过以下两种方式来实现: 利用 HttpResponse 对象下载文件 我们可以通过 Response 对象将文件以指定的方式输出到浏…

    C# 2023年6月3日
    00
  • C# menuStrip控件实现鼠标滑过自动弹出功能

    让我来为你详细讲解“C# menuStrip控件实现鼠标滑过自动弹出功能”的完整攻略。 一、前置知识 在学习本攻略前,我们需要先掌握以下知识: C#语言的基础语法和控件的使用方法; menuStrip控件的基本使用方法; 鼠标事件相关的知识。 二、实现过程 首先,我们需要在窗体上添加menuStrip控件,并在其中添加菜单项。在代码中,我们可以通过以下方法来…

    C# 2023年6月3日
    00
  • jQuery使用$.ajax进行即时验证实例详解

    让我来详细讲解“jQuery使用$.ajax进行即时验证实例详解”。 标题 首先,我们需要了解一下什么是jQuery以及$.ajax。jQuery是一个快速且简洁的JavaScript库,它简化了HTML文档遍历、事件处理、动画等操作。而$.ajax是jQuery中一个重要的函数,用来进行异步请求,可以实现无需刷新页面即可获取/修改数据。 具体步骤 在实现即…

    C# 2023年6月8日
    00
  • C#查找对象在ArrayList中出现位置的方法

    Markdown格式说明: 标题使用#号进行标记 代码块使用“`标记开头和结尾 示例说明使用文本加代码块结合的方式 C#查找对象在ArrayList中出现位置的方法 在 C# 中,可以使用 ArrayList 类型来存储一些对象。有时候我们需要查找某个对象在 ArrayList 中出现的位置,这时候可以使用以下方法对 ArrayList 进行搜索: int…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部