惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
D
DataBreaches.Net
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
Docker
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
Check Point Blog
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
IT之家
IT之家
月光博客
月光博客
U
Unit 42
K
Kaspersky official blog
T
Threatpost
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
GbyAI
GbyAI
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
云风的 BLOG
云风的 BLOG
酷 壳 – CoolShell
酷 壳 – CoolShell
I
InfoQ
Engineering at Meta
Engineering at Meta
Recorded Future
Recorded Future
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Security @ Cisco Blogs
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
Security Archives - TechRepublic
Security Archives - TechRepublic
Webroot Blog
Webroot Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Schneier on Security
S
Secure Thoughts
The Register - Security
The Register - Security
B
Blog RSS Feed
The Last Watchdog
The Last Watchdog
P
Palo Alto Networks Blog
爱范儿
爱范儿
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
N
News and Events Feed by Topic
阮一峰的网络日志
阮一峰的网络日志
L
LINUX DO - 热门话题
C
Cisco Blogs
Spread Privacy
Spread Privacy
F
Full Disclosure
博客园 - 聂微东
T
The Blog of Author Tim Ferriss

博客园 - shawnliu

log4net使用guidline(写的很详细) Log4net 简明手册(来自yuhen,写的非常好) 浅谈大型网站动态应用系统架构 使用cfengine来实现服务器的自动化配置 - shawnliu - 博客园 CodeDOM & Emit & MSIL SQL Server中奇妙的NULL 什么是Landing Page? sql server apply与 join等的区别 老是在select中丢掉了NOLOCK有啥后果???deadlock ooo scope_identity(), @@IDENTITY, IDENT_CURRENT()区别 Introduction to SQL SQL Server Indexes [A good reference] 大众点评的年会视频 很搞 十二种标题编写方法,让你流量暴涨[zz] (测试小程序)使用XmlSerializer来连接xml config文件和类 正则表达式 1个月100万封邮件营销实战及总结[zz] B2C Opinions 年薪12万的乞丐给我上了震撼的一课 Eliminate the Use of Temporary Tables For HUGE Performance Gains
如何在.NET中实现脚本引擎 (CodeDom篇)
shawnliu · 2010-06-12 · via 博客园 - shawnliu

 .NET 本身提供了强大的脚本引擎,可以直接使用.NET CLR的任何编程语言作为脚本语言,如VB.NET、C#、JScript, J#等等。使用脚本引擎,我们可以动态生成任意表达式、或动态导入任意脚本文件,并在任意时候执行。 
        经实践发现,我们可以使用至少两种不同的方式在.NET中使用脚本引擎:VsaEngine和CodeDom。 
        其实,CodeDom不能算是真正的脚本引擎,它实际上是编译器。但是我们完全可以利用CodeDom来模拟脚本引擎。 
        使用Emit方法也能达到动态生成可执行代码的目的,而且Emit生成的代码不需要编译,因此速度更快。但是Emit插入的实际上是汇编代码,不能算是脚本语言。 
        本文介绍如何以CodeDom方式来动态生成可执行代码。

(Teeta无法发布完整的文章,有兴趣查看整篇文章,请到:http://ly4cn.cnblogs.com/archive/2005/11/03/267989.html

    1.     构造一个编译器

  • 设置编译参数 
    编译参数需要在CompilerParameters设置: 
CompilerOptions用于设置编译器命令行参数
IncludeDebugInformation用于指示是否在内存在生成Assembly
GenerateInMemory用于指示是否在内存在生成Assembly
GenerateExecutable用于指示生成的Assembly类型是exe还是dll
OutputAssembly用于指示生成的程序文件名(仅在GenerateInMemory为false的情况)
ReferencedAssemblies用于添加引用Assembly

例如:

theParameters.ReferencedAssemblies.Add("System.dll"); 

  • 创建指定语言的编译器 
    编译需要由指定语言的CodeDomProvider生成。

这里列举一些.NET的CodeDomProvider:        

vb.net Microsoft.VisualBasic.VBCodeProvider
C#Microsoft.CSharp.CSharpCodeProvider
jscriptMicrosoft.JScript.JScriptCodeProvider
J#Microsoft.VJSharp.VJSharpCodeProvider

以C#为例,要创建C#编译器,代码如下: 

ICodeCompiler compiler = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler(); 

下面是完整的创建编译器的例子:

        /// 

 
        
/// 创建相应脚本语言的编译器 
        
///  
        private void createCompiler(string strLanguage, bool debugMode, string strAssemblyFileName) 
        

            
this.theParameters = new CompilerParameters(); 
            
this.theParameters.OutputAssembly = System.IO.Path.Combine(System.IO.Path.GetTempPath(), strAssemblyFileName + ".dll"); 
            
this.theParameters.GenerateExecutable = false
            
this.theParameters.GenerateInMemory = true
            
if(debugMode) 
            

                
this.theParameters.IncludeDebugInformation = true
                
this.theParameters.CompilerOptions += "/define:TRACE=1 /define:DEBUG=1 "
            }
 
            
else 
            

                
this.theParameters.IncludeDebugInformation = false
                
this.theParameters.CompilerOptions += "/define:TRACE=1 "
            }
 
 
            AddReference(
"System.dll"); 
            AddReference(
"System.Data.dll"); 
            AddReference(
"System.Xml.dll"); 
 
            strLanguage 
= strLanguage.ToLower(); 
 
            CodeDomProvider theProvider; 
 
            
if("visualbasic" == strLanguage || "vb" == strLanguage) 
            

                theProvider 
= new Microsoft.VisualBasic.VBCodeProvider(); 
                
if(debugMode) 
                    theParameters.CompilerOptions 
+= "/debug:full /optimize- /optionexplicit+ /optionstrict+ /optioncompare:text /imports:Microsoft.VisualBasic,System,System.Collections,System.Diagnostics "
                
else 
                    theParameters.CompilerOptions 
+= "/optimize /optionexplicit+ /optionstrict+ /optioncompare:text /imports:Microsoft.VisualBasic,System,System.Collections,System.Diagnostics "
                AddReference(
"Microsoft.VisualBasic.dll"); 
            }
 
            
else if("jscript" == strLanguage || "js" == strLanguage) 
            

                theProvider 
= new Microsoft.JScript.JScriptCodeProvider(); 
                AddReference(
"Microsoft.JScript.dll"); 
            }
 
            
else if("csharp" == strLanguage || "cs" == strLanguage || "c#" == strLanguage) 
            

                theProvider 
= new Microsoft.CSharp.CSharpCodeProvider(); 
                
if(!debugMode) 
                    theParameters.CompilerOptions 
+= "/optimize "
            }
 
//            else if("jsharp" == strLanguage || "vj" == strLanguage || "j#" == strLanguage) 
//            { 
//                theProvider = new Microsoft.VJSharp.VJSharpCodeProvider(); 
//                if(!debugMode) 
//                    theParameters.CompilerOptions += "/optimize "; 
//            } 
            else 
                
throw new System.Exception("指定的脚本语言不被支持。"); 
 
            
this.theCompiler = theProvider.CreateCompiler();             
        }
 
 
        
///  
        
/// 添加引用对象。 
        
///  
        
/// 引用的文件名
 
        public void AddReference(string __strAssemblyName) 
        

            theParameters.ReferencedAssemblies.Add(__strAssemblyName); 
        }
 

2.     编译源代码 

        编译源代码相当简单,只需一条语句就搞定了:

CompilerResults compilerResults  = compiler.CompileAssemblyFromSource(this.theParameters, this.SourceText); 

执行后,可以从compilerResults取得以下内容: 

NativeCompilerReturnValue编译结果,用于检查是否成功
Errors编译时产生的错误和警告信息
CompiledAssembly如果编译成功,则返回编译生成的Assembly

  
示例函数: 

        /// 


        
/// 编译脚本。编译前将清空以前的编译信息。
        
/// CompilerInfo将包含编译时产生的错误信息。
        
/// 
        
/// 成功时返回True。不成功为False。
        public bool Compile()
        
{
            
this.theCompilerInfo = "";
            
this.isCompiled = false;
            
this.theCompiledAssembly = null;
            
this.theCompilerResults = this.theCompiler.CompileAssemblyFromSource(this.theParameters, this.SourceText);

            
if(this.theCompilerResults.NativeCompilerReturnValue == 0)
            
{
                
this.isCompiled = true;
                
this.theCompiledAssembly = this.theCompilerResults.CompiledAssembly;
            }


            System.Text.StringBuilder compilerInfo 
= new System.Text.StringBuilder();

            
foreach(CompilerError err in this.theCompilerResults.Errors)
            
{
                compilerInfo.Append(err.ToString());
                compilerInfo.Append(
"\r\n");
            }


            theCompilerInfo 
= compilerInfo.ToString();

            
return isCompiled;
        }

    3.     执行代码 

使用Reflection机制就可以很方便的执行Assembly中的代码。 
我们假设编译时使用的脚本代码 this.SourceText 内容如下:

namespace test 

    
public class script 
    

        
static public void Main() 
        

            MessageBox.Show(
"Hello"); 
        }
 
    }
 
}
 

则相应的执行代码为: 

scriptEngine.Invoke("test.script""Main"null);

Invoke函数内容:

        /// <summary>
        
/// 执行指定的脚本函数(Method)。
        
/// 如果指定的类或模块名,以及函数(Method)、或参数不正确,将会产生VsaException/VshException例外。
        
/// </summary>
        
/// <param name="__strModule">类或模块名</param>
        
/// <param name="__strMethod">要执行的函数(Method)名字</param>
        
/// <param name="__Arguments">参数(数组)</param>
        
/// <returns>返回执行的结果</returns>

        public object Invoke(string __strModule, string __strMethod, object[] __Arguments)

posted on 2010-06-12 00:56  shawnliu  阅读(676)  评论()    收藏  举报