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

yizhihongxing

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日

相关文章

  • .NET Core实现企业微信消息推送

    . 确定需求 首先,我们需要明确要实现的需求是什么,即企业微信消息推送。 #. 了解企业微信 需要了解微信企业号,术语翻译:公共账号(公众号)=企业号,开发文档:https://work.weixin.qq.com/api/doc#12977 #. 了解企业微信API 企业微信API包含了企业微信端所有的操作,例如成员管理、部门管理、消息通知等等,其接口文档…

    C# 2023年6月3日
    00
  • C# 格式化JSON的两种实现方式

    C#中格式化JSON常用于将数据序列化为JSON字符串发送到网络或存储到磁盘中。本文将为你介绍两种C#格式化JSON的实现方式。 1. 使用Newtonsoft.Json库 Newtonsoft.Json库是C#中广泛使用的JSON库。通过使用Newtonsoft.Json库,我们能够轻松地将数据序列化为JSON字符串,并对JSON字符串进行反序列化操作。 …

    C# 2023年6月3日
    00
  • C#实现简单过滤非法字符实例

    下面是对该问题的详细讲解: 1.背景介绍 在许多场景下,需要对用户输入的数据进行过滤,以防止非法字符的出现。这时候一个比较常见的做法就是使用正则表达式对用户输入的字符串进行校验,屏蔽非法字符,这样既保证了数据的正确性,也提升了应用程序的安全性。 本篇攻略就是介绍如何使用C#编程语言实现简单的过滤非法字符功能。 2.实现过程 2.1 初步设计 在C#中,我们可…

    C# 2023年6月7日
    00
  • C#编程总结(一)序列化总结

    下面是关于“C#编程总结(一)序列化总结”的完整攻略,包含两个示例。 1. 序列化总结 在C#编程中,序列化是将对象转换为可存储或可传输格式的过程。反序列化是将序列化的数据转换回对象的过程。C#提供了多种序列化方式,包括二进制序列化、XML序列化和JSON序列化等。以下是C#编程中序列化的总结: 1.1 二进制序列化 二进制序列化是将对象转换为二进制格式的过…

    C# 2023年5月15日
    00
  • Unity 使用tiledmap解析地图的详细过程

    下面我将为你详细讲解Unity使用TiledMap解析地图的详细过程。 1. 安装TiledMap插件 首先需要在Unity中安装TiledMap插件,步骤如下: 进入Unity Asset Store,搜索“Tiled2Unity”并下载安装。 安装完成后,在Unity的菜单栏中选择“Tiled2Unity” > ”Import Tiled Map“…

    C# 2023年6月3日
    00
  • C# Remove(TKey):从 IDictionary中移除具有指定键的元素

    当我们想要从C#的Dictionary类实例中删除一个指定键值对时,可以使用Remove(TKey)方法。Remove()方法接受一个TKey类型的参数,即要删除的键,如果该键存在于Dictionary中,就会将其对应的键值对移除,否则不会产生任何效果。此方法会返回一个bool值,表示是否成功删除指定键值对。 在使用Remove(TKey)方法时,需要先确保…

    C# 2023年4月19日
    00
  • .NET 6新特性试用之Nuget包验证

    .NET 6 新特性试用之 Nuget 包验证攻略 Nuget 包是 .NET 开发中不可或缺的一部分,它们提供了许多有用的功能和工具,可以帮助我们更轻松地开发 .NET 应用程序。在 .NET 6 中,有一些新的 Nuget 包验证特性,可以帮助我们更好地管理和验证我们的 Nuget 包。以下是 .NET 6 新特性试用之 Nuget 包验证的完整攻略: …

    C# 2023年5月17日
    00
  • asp中用insert into语句向数据库插入记录(添加信息)的方法

    以下是详细讲解“asp中用insert into语句向数据库插入记录(添加信息)的方法”的完整攻略: 1. 连接数据库 在使用insert into语句插入记录之前,我们需要首先连接到数据库,使用ADODB.Connection对象可以实现数据库连接。连接数据库的代码如下: <% ‘Recordset对象用于存储和处理从数据库中检索出来的数据 Dim …

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