- 浏览: 3047617 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
链接:Evaluating Mathematical Expressions by Compiling C# Code at Runtime, by Marcin Cuprjak (aka Vlad Tepes)
本文只是上面链接里的文章的C# 3.0翻新版。主要是引用过来,为了另一篇文章的需要而将System.CodeDom部分的例子分离到这边来讲。
下面的代码里用到了C# 3.0的类型推导(var关键字),也用到了C#一直都有的verbatim string,不过JavaEye这里的语法高亮程序显然没能处理好这部分的高亮……将就看吧。
我们总是有使用桌面计算器的需求。很多时候,我都会找一个带有交互式环境的解释器的脚本语言来充当桌面计算器。
当然我们总是可以直接写一个表达式解析器来做一个完整的计算器,但那样太麻烦了。本文所演示的,是直接使用C#的表达式,动态生成一个能运算用户指定的表达式的小程序。
假如说我们要计算一个函数的值:
但是我们在编译时还不知道f()函数的定义,而且希望由用户在运行时输入函数定义,则我们可以按顺序来做这么几件事:
1、让用户输入一个表达式作为函数的定义
2、把函数在内存里编译
3、让用户输入x和y的值,并调用函数
4、处理函数的返回结果
在.NET里,让现成的编译器来做这件事非常的简单。首先我们定义一个基类,包含有一个计算表达式的函数的stub:
EvaluatorBase.cs
然后我们定义一个类来实现对表达式的in-memory编译,如下。这里用到了反射和System.CodeDom来生成代码。在Initialize()方法里,假如编译成功则返回真,失败则返回假。留意到“源代码”是一个字符串,中间留了个空,让用户来填充。
Program.cs, part 1
接下来只要使用上面的类就行。在下面的驱动类里与用户交互,进行输入输出,并计算结果:
Program.cs, part 2
试验一下程序的运行:
也验证一下出错时会怎样:
嘛,我是在简体中文的Windows XP上运行这程序,所以错误提示里出现了中文……
Anyway,作为桌面计算器上面的代码还是太简陋了。本文只是要做个使用System.CodeDom的例子。
在上面的使用场景中,由于我们无法在运行前得知函数的定义,所以有些错误带到了运行时才能发现也不算是坏事。但假如我们使用System.CodeDom生成代码前就能知道完整的源代码是怎样的,那么让源代码放在字符串里显然不够好——类型安全消失了,IDE等开发工具的支持也没了,因为我们所有的待编译代码都在字符串里。
如果有办法既能在运行时才编译代码,又能在编译时就发现语法错误,那就……请期待下一篇文~
本文只是上面链接里的文章的C# 3.0翻新版。主要是引用过来,为了另一篇文章的需要而将System.CodeDom部分的例子分离到这边来讲。
下面的代码里用到了C# 3.0的类型推导(var关键字),也用到了C#一直都有的verbatim string,不过JavaEye这里的语法高亮程序显然没能处理好这部分的高亮……将就看吧。
我们总是有使用桌面计算器的需求。很多时候,我都会找一个带有交互式环境的解释器的脚本语言来充当桌面计算器。
当然我们总是可以直接写一个表达式解析器来做一个完整的计算器,但那样太麻烦了。本文所演示的,是直接使用C#的表达式,动态生成一个能运算用户指定的表达式的小程序。
假如说我们要计算一个函数的值:
z = f(x, y)
但是我们在编译时还不知道f()函数的定义,而且希望由用户在运行时输入函数定义,则我们可以按顺序来做这么几件事:
1、让用户输入一个表达式作为函数的定义
2、把函数在内存里编译
3、让用户输入x和y的值,并调用函数
4、处理函数的返回结果
在.NET里,让现成的编译器来做这件事非常的简单。首先我们定义一个基类,包含有一个计算表达式的函数的stub:
EvaluatorBase.cs
namespace MathEvaluator { public class EvaluatorBase { public virtual double Eval( double x, double y ) { return 0.0; // return dummy value for this base class } } }
然后我们定义一个类来实现对表达式的in-memory编译,如下。这里用到了反射和System.CodeDom来生成代码。在Initialize()方法里,假如编译成功则返回真,失败则返回假。留意到“源代码”是一个字符串,中间留了个空,让用户来填充。
Program.cs, part 1
using System; using System.CodeDom.Compiler; using Microsoft.CSharp; namespace MathEvaluator { public class MathExpressionEvaluator { private EvaluatorBase m_evaluator; public bool Initialize( string expression ) { var compiler = new CSharpCodeProvider( ); var options = new CompilerParameters( ); // set compile options options.GenerateExecutable = false; options.GenerateInMemory = true; options.ReferencedAssemblies.Add( "System.dll" ); options.ReferencedAssemblies.Add( this.GetType( ).Assembly.Location ); // set the source code to compile var source = @"using System; using MathEvaluator; public class UserExpressionEvaluator : MathEvaluator.EvaluatorBase { public override double Eval( double x, double y ) { return " + expression + @"; } }"; // compile the code, on-the-fly var result = compiler.CompileAssemblyFromSource( options, source ); // print errors foreach ( var error in result.Errors ) Console.WriteLine( error ); // if compilation sucessed if ( ( !result.Errors.HasErrors ) && ( result.CompiledAssembly != null ) ) { var type = result.CompiledAssembly.GetType( "UserExpressionEvaluator" ); try { if ( type != null ) this.m_evaluator = Activator.CreateInstance( type ) as EvaluatorBase; } catch ( Exception ex ) { Console.WriteLine( ex ); return false; // something went wrong with the type } return true; } // compilation failed return false; } public double Eval( double x, double y ) { if ( this.m_evaluator != null ) return this.m_evaluator.Eval( x, y ); return 0.0; } }
接下来只要使用上面的类就行。在下面的驱动类里与用户交互,进行输入输出,并计算结果:
Program.cs, part 2
class Program { static void Main( string[ ] args ) { var evaluator = new MathExpressionEvaluator( ); Console.WriteLine( "Enter a math expression," + " with 2 parameters available (x and y): " ); string expression = Console.ReadLine( ); if ( evaluator.Initialize( expression ) ) { Console.Write( "Enter x: " ); var x = Convert.ToInt32( Console.ReadLine( ).Trim( ) ); Console.Write( "Enter y: " ); var y = Convert.ToInt32( Console.ReadLine( ).Trim( ) ); Console.WriteLine( "The result is: {0}", evaluator.Eval( x, y ).ToString( ) ); } else { Console.WriteLine( "The expression is either unsupported" + " or contains syntax error(s)."); } } } }
试验一下程序的运行:
引用
Enter a math expression, with 2 parameters available (x and y):
x + Math.Sin(y)
Enter x: 1
Enter y: 2
The result is: 1.90929742682568
x + Math.Sin(y)
Enter x: 1
Enter y: 2
The result is: 1.90929742682568
也验证一下出错时会怎样:
引用
Enter a math expression, with 2 parameters available (x and y):
(x + 1)) / y
d:\temp\lbfxtper.0.cs(5,39) : error CS1002: 应输入 ;
d:\temp\lbfxtper.0.cs(5,39) : error CS1525: 无效的表达式项“)”
The expression is either unsupported or contains syntax error(s).
(x + 1)) / y
d:\temp\lbfxtper.0.cs(5,39) : error CS1002: 应输入 ;
d:\temp\lbfxtper.0.cs(5,39) : error CS1525: 无效的表达式项“)”
The expression is either unsupported or contains syntax error(s).
嘛,我是在简体中文的Windows XP上运行这程序,所以错误提示里出现了中文……
Anyway,作为桌面计算器上面的代码还是太简陋了。本文只是要做个使用System.CodeDom的例子。
在上面的使用场景中,由于我们无法在运行前得知函数的定义,所以有些错误带到了运行时才能发现也不算是坏事。但假如我们使用System.CodeDom生成代码前就能知道完整的源代码是怎样的,那么让源代码放在字符串里显然不够好——类型安全消失了,IDE等开发工具的支持也没了,因为我们所有的待编译代码都在字符串里。
如果有办法既能在运行时才编译代码,又能在编译时就发现语法错误,那就……请期待下一篇文~
发表评论
-
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22388(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对象的重量
2011-08-21 17:15 0http://domino.research.ibm.com/ ... -
GetCustomAttribute()每次都返回新Attribute实例
2009-11-10 10:30 0Jeffrey Zhao: 一次失败的尝试(上):原来GetC ... -
委托与方法和隐藏参数
2009-09-07 15:32 3304之前正好发了些帖子是关于CLR里的委托的,然后看到老赵说事件也 ... -
要让CLR挂掉的话(第二弹)……
2009-09-04 03:26 12870(Disclaimer:如果需要转 ... -
要让CLR挂掉的话……
2009-09-02 16:53 4775(Disclaimer:如果需要转载请先与我联系。 作者:Re ... -
趣味编程:函数式链表的快速排序
2009-08-31 08:53 3444(恢复自2009-08-28的备份 ... -
事件处理器导致内存泄漏
2009-08-25 15:03 0Memory leak via event handlers ... -
C# 3.0的类型推导
2009-08-23 12:24 0Howard Dierking: Lambda, Lambda ... -
把lock的意思给弄混了 T T
2009-08-20 17:49 2597悲剧啊……前几天有个同学不停问我Java里的同步问题,今天写C ... -
把IEnumerable<T>和IObservable<T>粘起来?
2009-07-23 03:02 0Channel 9: Expert to Expert: Br ... -
Scott Peterson: Variance, Thy Name is Ambiguity
2009-07-01 23:49 1634原文作者:Scott Peterson 原文地址:http:/ ... -
void无法协变
2009-06-30 11:17 0Eric Lippert The void is invari ... -
同一个表达式算出来的浮点数结果会不相等?
2009-05-30 03:27 0浮点数有很多可把玩的地方。例如下面这段C程序: #includ ... -
C#开始默认引用Microsoft.CSharp.dll
2009-05-20 16:14 0记得VB6的运行时么?留意到VB.NET的程序都需要额外的VB ... -
反射与显式实现接口的方法
2009-05-20 11:43 4055在前一帖里,我用到了下面三处Expression.Call() ... -
看到一个关于ref参数与多态的问题,记一下
2009-05-18 10:48 1940刚才读到Alan McGovern的一帖,问为什么形式参数是r ... -
C#的+=运算符两例
2009-05-06 18:18 2031刚偶尔看到了justjavac写的java解惑 - 半斤八两( ...
相关推荐
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "2.0.0.0")] [Serializable()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Component...
例如,要使用CodeDom生成一个简单的C#类,你可以首先创建一个`CodeCompileUnit`对象,然后添加一个`CodeNamespace`,接着在命名空间中添加`CodeTypeDeclaration`表示类,最后在类中添加`CodeMemberMethod`表示方法。...
下面是一个简单的使用样例: ```csharp using System; using System.Web.Services.Description; using System.CodeDom; using Microsoft.CSharp; using System.CodeDom.Compiler; class Program { static void ...
Sandcastle 帮助文档 The topics in this section describe the various changes made to the Web Code Providers library over the life of the project.
首先,创建编译器实例,然后将字符串编译成一个类,最后使用反射来调用该类中的方法。 动态生成类可以提高代码的灵活性和可维护性,但需要注意的是,动态生成类可能会对性能产生一些影响。因此,在使用动态生成类时...
一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 StronglyTypedResourceBuilder // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,...
/// 一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 StronglyTypedResourceBuilder // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX ...
.NET 提供了一个System.CodeDom的命名空间,它允许用户动态编译和创建程序集。本文提供了有关如何动态创建程序集的内容。 用途 1、模板化代码生成:生成适用于 ASP.NET、XML Web 服务客户端代理、代码向导、设计器或...
例如,我们可以使用CSharpCodeProvider创建一个代码提供者,然后将字符串形式的C#代码传入,编译成一个Assembly。 三、Roslyn编译API 微软的Roslyn项目为C#和VB.NET提供了开源的编译器API,这使得动态编译变得更加...
每个代码生成器可根据“代码文档对象模型”(CodeDOM) 源代码模型的结构(由System.CodeDom命名空间所提供的元素组成),用特定的某种编程语言生成源代码。 System.Collections:包含定义各种对象集合(如列表、...
总的来说,这个压缩包可能包含了一个使用CodeDom进行动态代码生成和编译的.NET项目,项目可能涉及Windows Forms应用、VSA脚本支持以及动态生成的源代码。CodeDom的强大之处在于其灵活性和跨语言性,使得开发更加便捷...
下面是一个简单的 CodeDom 示例代码片段,用于演示如何使用 CodeDom 创建一个包含命名空间、类和导入语句的代码单元。 ```csharp // 创建 CodeCompileUnit 对象 CodeCompileUnit classCompileUnit = new ...
为了更好地理解和使用CodeDOM,我们可以通过一个简单的示例来展示其基本用法: ```csharp using System; using System.CodeDom; using System.CodeDom.Compiler; using Microsoft.CSharp; using System.IO; using ...
以下是使用System.CodeDom.Compiler命名空间进行动态编译的一个示例: ```csharp using System; using System.CodeDom.Compiler; using System.Data; using System.Xml; using System.Diagnostics; // 创建代码...
- 然后,使用`System.CodeDom.Compiler.CodeDomProvider`和`System.CodeDom.Compiler.CompilerResults`来编译这个元数据为实际的代理类。 2. **创建通道工厂:** - 使用`System.ServiceModel.ChannelFactory...
.NET Framework 是一个全面的开发平台,它包含了丰富的类库,为开发者提供了许多命名空间,以支持不同领域的编程需求。命名空间是一种组织代码的方式,它帮助开发者更好地管理和使用类与方法,避免命名冲突。 1. ...
在本示例中,`ClassGenerator`可能是实现CodeDom功能的一个类,用于生成C#类的源代码。通常,`ClassGenerator`会包含一系列方法,用于创建CodeDom对象,如创建`CodeTypeDeclaration`表示类,`CodeMemberMethod`表示...
.NET框架提供了一个强大的工具——`System.CodeDom.Compiler`命名空间,它包含了用于编译源代码的能力。主要使用`CodeDomProvider`类来生成IL(中间语言)代码,然后通过`CompileAssemblyFromSource`或`...
它提供了一系列接口和类来生成和编译源代码。这对于那些需要动态生成和编译代码的应用场景非常有用。 #### System.Collections System.Collections 命名空间提供了各种集合类,包括 List、Dictionary、Queue 等,...