C# 脚本化实现方式探究
文章目录
- C# 脚本化
- 使用 CodeDom
- Roslyn
- Microsoft Roslyn vs. CodeDom
- 第三方工具库
- 实现方式
- 样例展示
C# 脚本化
.NET 编译平台介绍:
https://docs.microsoft.com/zh-cn/dotnet/csharp/roslyn-sdk/
使用 CodeDom
CodeDOM 提供表示多种常见源代码元素的类型。 可以设计一个程序,它使用 CodeDOM 元素生成源代码模型来组合对象图。 对于支持的编程语言,可使用 CodeDOM 代码生成器将此对象图呈现为源代码。 还可使用 CodeDOM 将源代码编译为二进制程序集。
CodeDOM 的常见用途包括:
- 模板化代码生成:生成适用于 ASP.NET、XML Web 服务客户端代理、代码向导、设计器或其他代码发出机制的代码。
- 动态编译:支持一种或多种语言的代码编译。
相关介绍:https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/using-the-codedom
Roslyn
Roslyn为开源C#和Visual Basic编译器提供了丰富的代码分析API。 它支持使用Visual Studio使用的相同API构建代码分析工具
开源地址:https://github.com/dotnet/roslyn
Microsoft Roslyn vs. CodeDom
关于 Roslyn
和 CodeDom
不同可以参考地址:
https://stackoverflow.com/questions/7852926/microsoft-roslyn-vs-codedom
第三方工具库
开源地址:https://github.com/oleg-shilo/cs-script
CS-Script是一个基于CLR的脚本系统,它使用符合ECMA的C#作为编程语言。
CS-Script允许无缝切换底层编译技术,而不会影响代码库。 目前支持的编译器是Mono,Roslyn和CodeDOM
实现方式
参见接口 IEvaluator.cs
。具体实现在注释中有介绍
public interface IEvaluator{/// <summary>/// Gets or sets a value indicating whether to compile script with debug symbols./// <para>Note, affect of setting <c>DebugBuild</c> will always depend on the compiler implementation:/// <list type="bullet">/// <item><term>CodeDom</term><description>Fully supports. Generates debugging symbols (script can be debugged) and defines <c>DEBUG</c> and <c>TRACE</c> conditional symbols</description> </item>/// <item><term>Mono</term><description>Partially supports. Defines <c>DEBUG</c> and <c>TRACE</c> conditional symbols</description> </item>/// <item><term>Roslyn</term><description>Doesn't supports at all.</description> </item>/// </list>/// </para>/// </summary>/// <value><c>true</c> if 'debug build'; otherwise, <c>false</c>.</value>bool? DebugBuild { get; set; }/// <summary>/// Gets or sets the flag indicating if the script code should be analyzed and the assemblies/// that the script depend on (via '//css_...' and 'using ...' directives) should be referenced./// </summary>/// <value></value>bool DisableReferencingFromCode { get; set; }/// <summary>/// Evaluates (compiles) C# code (script). The C# code is a typical C# code containing a single or multiple class definition(s)./// </summary>/// <example>///<code>/// Assembly asm = CSScript.Evaluator/// .CompileCode(@"using System;/// public class Script/// {/// public int Sum(int a, int b)/// {/// return a+b;/// }/// }");////// dynamic script = asm.CreateObject("*");/// var result = script.Sum(7, 3);/// </code>/// </example>/// <param name="scriptText">The C# script text.</param>/// <returns>The compiled assembly.</returns>Assembly CompileCode(string scriptText);/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>) and evaluates it./// <para>/// This method is a logical equivalent of <see cref="CSScriptLibrary.IEvaluator.CompileCode"/> but is allows you to define/// your script class by specifying class method instead of whole class declaration.</para>/// </summary>/// <example>///<code>/// dynamic script = CSScript.Evaluator/// .CompileCode(@"int Sum(int a, int b)/// {/// return a+b;/// }")/// .CreateObject("*");////// var result = script.Sum(7, 3);/// </code>/// </example>/// <param name="code">The C# code.</param>/// <returns>The compiled assembly.</returns>Assembly CompileMethod(string code);/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads the class to the current AppDomain./// <para>Returns non-typed <see cref="CSScriptLibrary.MethodDelegate"/> for class-less style of invoking.</para>/// </summary>/// <example>/// <code>/// var log = CSScript.Evaluator/// .CreateDelegate(@"void Log(string message)/// {/// Console.WriteLine(message);/// }");////// log("Test message");/// </code>/// </example>/// <param name="code">The C# code.</param>/// <returns> The instance of a 'duck typed' <see cref="CSScriptLibrary.MethodDelegate"/></returns>MethodDelegate CreateDelegate(string code);/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads the class to the current AppDomain./// <para>Returns typed <see cref="CSScriptLibrary.MethodDelegate{T}"/> for class-less style of invoking.</para>/// </summary>/// <typeparam name="T">The delegate return type.</typeparam>/// <example>/// <code>/// var product = CSScript.Evaluator/// .CreateDelegate<int>(@"int Product(int a, int b)/// {/// return a * b;/// }");////// int result = product(3, 2);/// </code>/// </example>/// <param name="code">The C# code.</param>/// <returns> The instance of a typed <see cref="CSScriptLibrary.MethodDelegate{T}"/></returns>MethodDelegate<T> CreateDelegate<T>(string code);/// <summary>/// Analyses the script code and returns set of locations for the assemblies referenced from the code with CS-Script directives (//css_ref)./// </summary>/// <param name="code">The script code.</param>/// <param name="searchDirs">The assembly search/probing directories.</param>/// <returns>Array of the referenced assemblies</returns>string[] GetReferencedAssemblies(string code, params string[] searchDirs);/// <summary>/// Returns set of referenced assemblies./// <para>/// Notre: the set of assemblies is cleared on Reset./// </para>/// </summary>/// <returns></returns>Assembly[] GetReferencedAssemblies();/// <summary>/// Evaluates and loads C# code to the current AppDomain. Returns instance of the first class defined in the code./// </summary>/// <example>The following is the simple example of the LoadCode usage:///<code>/// dynamic script = CSScript.Evaluator/// .LoadCode(@"using System;/// public class Script/// {/// public int Sum(int a, int b)/// {/// return a+b;/// }/// }");/// int result = script.Sum(1, 2);/// </code>/// </example>/// <param name="scriptText">The C# script text.</param>/// <param name="args">The non default constructor arguments.</param>/// <returns>Instance of the class defined in the script.</returns>object LoadCode(string scriptText, params object[] args);/// <summary>/// Evaluates and loads C# code to the current AppDomain. Returns instance of the first class defined in the code./// After initializing the class instance it is aligned to the interface specified by the parameter <c>T</c>./// <para><c>Note:</c> Because the interface alignment is a duck typing implementation the script class doesn't have to/// inherit from <c>T</c>.</para>/// </summary>/// <example>The following is the simple example of the interface alignment:///<code>/// public interface ICalc/// {/// int Sum(int a, int b);/// }/// ..../// ICalc calc = CSScript.Evaluator/// .LoadCode<ICalc>(@"using System;/// public class Script/// {/// public int Sum(int a, int b)/// {/// return a+b;/// }/// }");/// int result = calc.Sum(1, 2);/// </code>/// </example>/// <typeparam name="T">The type of the interface type the script class instance should be aligned to.</typeparam>/// <param name="scriptText">The C# script text.</param>/// <param name="args">The non default type <c>T</c> constructor arguments.</param>/// <returns>Aligned to the <c>T</c> interface instance of the class defined in the script.</returns>T LoadCode<T>(string scriptText, params object[] args) where T : class;/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads/// the class to the current AppDomain./// <para>Returns instance of <c>T</c> delegate for the first method in the auto-generated class.</para>/// </summary>/// <example>/// <code>/// var Product = CSScript.Evaluator/// .LoadDelegate<Func<int, int, int>>(/// @"int Product(int a, int b)/// {/// return a * b;/// }");////// int result = Product(3, 2);/// </code>/// </example>/// <param name="code">The C# code.</param>/// <returns>Instance of <c>T</c> delegate.</returns>T LoadDelegate<T>(string code) where T : class;/// <summary>/// Evaluates and loads C# code from the specified file to the current AppDomain. Returns instance of the first/// class defined in the script file./// </summary>/// <example>The following is the simple example of the interface alignment:///<code>/// dynamic script = CSScript.Evaluator/// .LoadFile("calc.cs");////// int result = script.Sum(1, 2);/// </code>/// </example>/// <param name="scriptFile">The C# script file.</param>/// <returns>Instance of the class defined in the script file.</returns>object LoadFile(string scriptFile);/// <summary>/// Evaluates and loads C# code from the specified file to the current AppDomain. Returns instance of the first/// class defined in the script file./// After initializing the class instance it is aligned to the interface specified by the parameter <c>T</c>./// <para><c>Note:</c> the script class does not have to inherit from the <c>T</c> parameter as the proxy type/// will be generated anyway.</para>/// </summary>/// <example>The following is the simple example of the interface alignment:///<code>/// public interface ICalc/// {/// int Sum(int a, int b);/// }/// ..../// ICalc calc = CSScript.Evaluator/// .LoadFile<ICalc>("calc.cs");////// int result = calc.Sum(1, 2);/// </code>/// </example>/// <typeparam name="T">The type of the interface type the script class instance should be aligned to.</typeparam>/// <param name="scriptFile">The C# script text.</param>/// <returns>Aligned to the <c>T</c> interface instance of the class defined in the script file.</returns>T LoadFile<T>(string scriptFile) where T : class;/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads/// the class to the current AppDomain./// </summary>/// <example>The following is the simple example of the LoadMethod usage:/// <code>/// dynamic script = CSScript.Evaluator/// .LoadMethod(@"int Product(int a, int b)/// {/// return a * b;/// }");////// int result = script.Product(3, 2);/// </code>/// </example>/// <param name="code">The C# script text.</param>/// <returns>Instance of the first class defined in the script.</returns>object LoadMethod(string code);/// <summary>/// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads/// the class to the current AppDomain./// <para>/// After initializing the class instance it is aligned to the interface specified by the parameter <c>T</c>./// </para>/// </summary>/// <example>The following is the simple example of the interface alignment:/// <code>/// public interface ICalc/// {/// int Sum(int a, int b);/// int Div(int a, int b);/// }/// ..../// ICalc script = CSScript.Evaluator/// .LoadMethod<ICalc>(@"public int Sum(int a, int b)/// {/// return a + b;/// }/// public int Div(int a, int b)/// {/// return a/b;/// }");/// int result = script.Div(15, 3);/// </code>/// </example>/// <typeparam name="T">The type of the interface type the script class instance should be aligned to.</typeparam>/// <param name="code">The C# script text.</param>/// <returns>Aligned to the <c>T</c> interface instance of the auto-generated class defined in the script.</returns>T LoadMethod<T>(string code) where T : class;/// <summary>/// References the assemblies from the script code./// <para>The method analyses and tries to resolve CS-Script directives (e.g. '//css_ref') and 'used' namespaces based on the/// optional search directories.</para>/// </summary>/// <param name="code">The script code.</param>/// <param name="searchDirs">The assembly search/probing directories.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssembliesFromCode(string code, params string[] searchDirs);/// <summary>/// References the given assembly by the assembly path./// <para>It is safe to call this method multiple times for the same assembly. If the assembly already referenced it will not/// be referenced again.</para>/// </summary>/// <param name="assembly">The path to the assembly file.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssembly(string assembly);/// <summary>/// References the given assembly./// <para>It is safe to call this method multiple times/// for the same assembly. If the assembly already referenced it will not/// be referenced again./// </para>/// </summary>/// <param name="assembly">The assembly instance.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssembly(Assembly assembly);/// <summary>/// References the name of the assembly by its partial name./// <para>Note that the referenced assembly will be loaded into the host AppDomain in order to resolve assembly partial name.</para>/// <para>It is an equivalent of <c>Evaluator.ReferenceAssembly(Assembly.LoadWithPartialName(assemblyPartialName))</c></para>/// </summary>/// <param name="assemblyPartialName">Partial name of the assembly.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssemblyByName(string assemblyPartialName);/// <summary>/// References the assembly by the given namespace it implements./// </summary>/// <param name="namespace">The namespace.</param>/// <param name="resolved">Set to <c>true</c> if the namespace was successfully resolved (found) and/// the reference was added; otherwise, <c>false</c>.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator TryReferenceAssemblyByNamespace(string @namespace, out bool resolved);/// <summary>/// References the assembly by the given namespace it implements./// <para>Adds assembly reference if the namespace was successfully resolved (found) and, otherwise does nothing</para>/// </summary>/// <param name="namespace">The namespace.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssemblyByNamespace(string @namespace);/// <summary>/// References the assembly by the object, which belongs to this assembly./// <para>It is safe to call this method multiple times/// for the same assembly. If the assembly already referenced it will not/// be referenced again./// </para>/// </summary>/// <param name="obj">The object, which belongs to the assembly to be referenced.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssemblyOf(object obj);/// <summary>/// References the assembly by the object, which belongs to this assembly./// <para>It is safe to call this method multiple times/// for the same assembly. If the assembly already referenced it will not/// be referenced again./// </para>/// </summary>/// <typeparam name="T">The type which is implemented in the assembly to be referenced.</typeparam>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceAssemblyOf<T>();/// <summary>/// References the assemblies the are already loaded into the current <c>AppDomain</c>./// </summary>/// <param name="assemblies">The type of assemblies to be referenced.</param>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>
#if net35IEvaluator ReferenceDomainAssemblies(DomainAssemblies assemblies);
#elseIEvaluator ReferenceDomainAssemblies(DomainAssemblies assemblies = DomainAssemblies.AllStaticNonGAC);#endif#if net35/// <summary>/// References the assemblies the are already loaded into the current <c>AppDomain</c>./// <para>This method is an equivalent of <see cref="CSScriptLibrary.IEvaluator.ReferenceDomainAssemblies"/>/// with the hard codded <c>DomainAssemblies.AllStaticNonGAC</c> input parameter./// </para>/// </summary>/// <returns>The instance of the <see cref="CSScriptLibrary.IEvaluator"/> to allow fluent interface.</returns>IEvaluator ReferenceDomainAssemblies();
#endif/// <summary>/// Resets Evaluator./// <para>/// Resetting means clearing all referenced assemblies, recreating evaluation infrastructure (e.g. compiler setting)/// and reconnection to or recreation of the underlying compiling services./// </para>/// <para>Optionally the default current AppDomain assemblies can be referenced automatically with/// <paramref name="referenceDomainAssemblies"/>.</para>/// </summary>/// <param name="referenceDomainAssemblies">if set to <c>true</c> the default assemblies of the current AppDomain/// will be referenced (see <see cref="ReferenceDomainAssemblies(DomainAssemblies)"/> method)./// </param>/// <returns>The freshly initialized instance of the <see cref="CSScriptLibrary.IEvaluator"/>.</returns>IEvaluator Reset(bool referenceDomainAssemblies = true);/// <summary>/// Clones the parent <see cref="CSScriptLibrary.IEvaluator"/>./// <para>/// This method returns a freshly initialized copy of the <see cref="CSScriptLibrary.IEvaluator"/>./// The cloning 'depth' can be controlled by the <paramref name="copyRefAssemblies"/>./// </para>/// <para>/// This method is a convenient technique when multiple <see cref="CSScriptLibrary.IEvaluator"/> instances/// are required (e.g. for concurrent script evaluation)./// </para>/// </summary>/// <param name="copyRefAssemblies">if set to <c>true</c> all referenced assemblies from the parent <see cref="CSScriptLibrary.IEvaluator"/>/// will be referenced in the cloned copy.</param>/// <returns>The freshly initialized instance of the <see cref="CSScriptLibrary.IEvaluator"/>.</returns>/// <example>///<code>/// var eval1 = CSScript.Evaluator.Clone();/// var eval2 = CSScript.Evaluator.Clone();////// var sub = eval1.LoadDelegate<Func<int, int, int>>(/// @"int Sub(int a, int b) {/// return a - b;/// }");////// var sum = eval2.LoadDelegate<Func<int, int, int>>(/// @"int Sub(int a, int b) {/// return a + b;/// }");////// var result = sum(7, sub(4,2));/// </code>/// </example>IEvaluator Clone(bool copyRefAssemblies = true);}
样例展示
源码链接: https://pan.baidu.com/s/1hGTA_ma2C3PAvdtaxnSg_g
提取码: v8jn
C# 脚本化实现方式探究相关推荐
- 脚本化HTTP 取得响应 指定请求
脚本化HTTP 下面将会用js代码操纵HTTP 下面将会说明在没有导致web浏览器重新加载任何窗口或者窗体的情况下,脚本实现web浏览器和服务器之间的通信. ajax:为一种找早起避免页面重载而动态更 ...
- 权威指南之脚本化jquery
jqury函数 jquery()($())有4种不同的调用方式 第一种是最常用的调用方式是传递css选择器(字符串)给$()方法.当通过这种方式调用时,$()方法会返回当前文档中匹配该选择器的元素集. ...
- 《守望先锋》中网络脚本化的武器和技能系统
在GDC2017[Networking Scripted Weapons and Abilities in Overwatch]的分享会上,来自暴雪的Dan Reed介绍了<守望先锋>中网 ...
- 《UnityAPI.ScriptableObject脚本化对象》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+CreateInstance+List+立钻哥哥++OK++)
<UnityAPI.ScriptableObject脚本化对象> 版本 作者 参与者 完成日期 备注 UnityAPI_ScriptableObject_V01_1.0 严立钻 2020. ...
- php服务器响应http请求,脚本化HTTP 取得响应 指定请求
脚本化HTTP 下面将会用js代码操纵HTTP 下面将会说明在没有导致web浏览器重新加载任何窗口或者窗体的情况下,脚本实现web浏览器和服务器之间的通信. ajax:为一种找早起避免页面重载而动态更 ...
- ajax将响应结果显示到iframe,脚本化HTTP 取得响应 指定请求
脚本化HTTP 下面将会用js代码操纵HTTP 下面将会说明在没有致使web浏览器从新加载任何窗口或者窗体的状况下,脚本实现web浏览器和服务器之间的通讯. ajax:为一种找早起避免页面重载而动态更 ...
- 27.大数据---Hive的数据库和表的基本操作;脚本化运行;内部表;外部表;分区表
一 . Hive 基本操作 1. 数据库操作(增.删.改.查) 1.1 创建数据库 create database if not exists test_001; 使用数据库 use test_001 ...
- 第17章 脚本化CSS
第17章 脚本化CSS CSS脚本化是网页交互效果的技术基础,使用CSS和JavaScript可以设计网页动画.利用脚本化CSS可以动态地改变HTML属性,如字体颜色.字体大小等,还可以用它设置和改变 ...
- Java脚本化编程实践整理 ScriptEngineManager万字详解
文章目录 认识 Java支持脚本语言的意义 Java对JavaScript的支持 Rhino/Nashorn概述 Nashorn的目的 实践操作 HelloWorld 执行脚本文件代码 脚本语言使用J ...
- 脚本化Questasim/Modelsim自动仿真——脱离联合仿真
目录 引言 脚本仿真步骤分析 完整的脚本代码 保姆级使用教程 扩展 引言 之前对于工程一直采用的是vivado+questasim联合仿真的模式,对于大型工程来说这个是合适的,因为需要调用一些ip库和 ...
最新文章
- 谷歌低调了 5 年的 Fuchsia OS,终于有望面世了!
- python线下培训-北京哪里有Python线下培训辅导班
- ajax路由器,注册ajax用户的步骤 _ 路由器设置|192.168.1.1|无线路由器设置|192.168.0.1 - 路饭网...
- Effective Java读书笔记六:方法
- java课程总结_java课程总结报告.doc
- iOS之深入解析weak关键字的底层原理
- 将亚型多态性与通用多态性相关联的危险
- 用PHP控制您的浏览器cache
- UI设计素材|等轴测图(2.5D插画)
- Java后台解决跨域问题
- 2017-2018-1 20155301 20155307 20155339 《信息安全系统设计基础》 实验一 开发环境的熟悉...
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
- matlab匹配滤波器的仿真
- InDesign(拼合预设转曲)
- 前端最新2022面试题(JS)
- 数理统计与数据分析第三版习题 第3章 第5题
- scratch中的植物大战僵尸之豌豆射手收集豌豆
- php header 生成pdf,PHP如何生成PDF文档
- win10锁定计算机后黑屏,win10锁定屏幕就黑屏怎么办
- 关于双向链表和二叉树链表的区别