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日

相关文章

  • 轻松学习C#的抽象类

    为了轻松学习C#的抽象类,您可以遵循以下步骤进行学习。 1.了解抽象类的定义和用途 抽象类是一个被声明为抽象的类,它不能被实例化,但是可以使用它的引用来引用其子类的对象。抽象类通常用于定义抽象方法,这些方法不包括任何实现细节,只是定义了子类必须实现的方法。抽象类还可以包括实现的方法和字段。 2.学习如何声明抽象类 要声明一个抽象类,您需要使用abstract…

    C# 2023年6月1日
    00
  • 一篇文章彻底搞清楚c#中的委托与事件

    一篇文章彻底搞清楚C#中的委托与事件 委托 委托(Delegate)是一种类型,它可以持有函数的引用并执行这个函数。通过委托,我们可以在不知道函数名的情况下,直接访问和执行函数。 定义 在C#中,委托是定义在类的外部,但是要在类的内部定义具体的委托实例。委托的定义格式如下: public delegate void DelegateName(paramete…

    C# 2023年6月7日
    00
  • Jexcel实现按一定规则分割excel文件的方法

    Jexcel是一种JavaScript库,用于在Web应用程序中创建和编辑Excel电子表格。本文将提供详细的“Jexcel实现按一定规则分割excel文件的方法”的完整攻略,包括什么是Jexcel、如何按一定规则分割excel文件以及两个示例。 什么是Jexcel? Jexcel是一种JavaScript库,用于在Web应用程序中创建和编辑Excel电子表…

    C# 2023年5月15日
    00
  • C#很简单而又很经典的一句代码实例

    当谈到 C# 语言的简洁性和经典性时,有一些令人惊艳的代码实例。以下是两个示例: 示例一:使用 LINQ 进行筛选 LINQ(Language-Integrated Query)是在 C# 中进行数据查询和操作的一种方式。在 LINQ 中,您可以使用像 SQL 语句一样的查询语法来筛选出特定的数据。下面是一段使用 LINQ 筛选出数字列表中所有偶数的代码: …

    C# 2023年5月15日
    00
  • C#实现下载网页HTML源码的方法

    下面是“C#实现下载网页HTML源码的方法”的完整攻略,具体流程如下: 1. 发送HTTP请求 使用C#自带的WebRequest类向目标网址发送HTTP请求,获取服务器响应。HTTP请求的方式分为GET和POST,这里以GET为例,构造请求如下: string url = "http://www.example.com"; WebReq…

    C# 2023年6月3日
    00
  • C#中哈希表(Hashtable)的介绍及简单用法

    C#中的哈希表(Hashtable)是一种集合类型,其存储方式是以键值对(Key-Value pair)的形式存储数据,键和值可以是任意类型。哈希表类似于字典,通过键来查找对应的值。 哈希表(Hashtable)的介绍 哈希表(Hashtable)是.NET Framework提供的一种强类型非泛型集合类型,它实现了IDictionary接口并使用键值对存储…

    C# 2023年6月3日
    00
  • C# 制作PictureBox圆形头像框并从数据库中读取头像

    这里是制作C# Windows Form应用程序中PictureBox圆形头像框并从数据库中读取头像的完整攻略。在这个攻略中,你将学习如何: 在Windows Form中创建一个PictureBox控件。 将PictureBox控件转换为圆形形状。 从数据库中读取图像数据,并将其显示在PictureBox控件中。 封装代码使其可以在多个窗体和应用程序中重复使…

    C# 2023年5月31日
    00
  • Blazor组件事件处理功能

    Blazor组件事件处理功能是指在Blazor应用中,可以通过组件级别的事件处理来响应用户的操作或操作结果。下面我将详细介绍它的完整攻略及两个示例说明。 Blazor组件事件处理功能完整攻略 Blazor组件事件处理功能主要分为以下几步: 第一步:定义组件 首先我们需要定义一个组件,并定义该组件内部需要使用的事件。可以通过以下方式定义事件: [Paramet…

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