扩展C#与元编程(一)
众所周知,Roslyn project已经开源一年多了。简单的说,Roslyn是:1)用C#/VB写的C#/VB的编译器,以及与IDE集成;2)编译器的功能以API的方式暴露出来(即一组DLL)。
Roslyn对大多数开发者来说没啥用处,你关心的是你的应用程序的逻辑与构建而不需要关心编译器是怎么运行的。有时你觉得C#/VB有需要增强的地方,于是你兴致勃勃的跑到Roslyn论坛去发表一个proposal,MS的guy会给你的issue打上Area-Language Design
的标签,网友们也许会来讨论一下,然后呢?就没有然后了,这有点像在求雨,下不下、什么时候下、下多大全凭神仙们(MS guys)的“心情”。
求人不如求己,既然Roslyn已经以MIT方式开源,咱们就站在巨人的肩膀上自己动手丰衣足食吧,也就是,扩展C#,做(屌丝级的)complier guy!
众所周知,C#是门general-purpose的编程语言,你想添加的feature既可以是general的,也可以是specific的。比如,XML literal是个general的C# feature,下两图展示了一个specific的feature,让C#支持Windows Workflow Foundation(WF)的activity:
其实,这不该叫“扩展C#”,而该叫做“创建一门衍生自C#的DSL”,如果你对WF感兴趣,请访问Metah.W: A Workflow Metaprogramming Language。
姑且就用“扩展C#”这个叫法。如上两图所示,Metah.W(MW)在C#中加入了activity的构造,在概念上,activity是C# class和function的合体,在图一中,public sealed class
摇身一变成为public sealed activity
,接着宣告activity的名字,小括号中宣告parameters,如string BookmarkName, string Text
,接着宣告可选的return type,如activity Prompt
的as int
宣告返回类型是int
,若无as XXX
宣告则返回void
。Activity的body中是变量的宣告和statement的使用,statement可以是:1)C# expression statement,如图一中的target = new Random().Next(1, MaxNumber) + 1;
;2)well-known statement,如if-else, while, do-while, foreach, try-catch-finally等;3)special statement,如图二中的statemachine
, delay
。因为activity是class和function的合体,可以调用它并将返回值赋给变量/参数,如guess = new Prompt().Invoke(...)
。
将FirstLook.mw送进MW编译器,将产生下面的C#代码:
//FirstLook.mw.cs, generated by the MW compiler
namespace HelloMW.FirstLook
{
public sealed class SequentialNumberGuess : global::System.Activities.Activity
{
public global::System.Activities.InArgument<int> MaxNumber { get; set; }
public global::System.Activities.OutArgument<int> Turns { get; set; }
private global::System.Activities.Activity __GetImplementation__()
{
global::System.Activities.Activity __vroot__;
{
var __v__0 = new global::System.Activities.Statements.Sequence();
var target = new global::System.Activities.Variable<int>();
__v__0.Variables.Add(target);
var guess = new global::System.Activities.Variable<int>();
__v__0.Variables.Add(guess);
__v__0.Activities.Add(new global::MetahWActionActivity(__ctx__ =>
{
target.SetEx(__ctx__, new Random().Next(1, MaxNumber.Get(__ctx__)) + 1);
}
));
var __v__1 = new global::System.Activities.Statements.DoWhile();
__v__1.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => guess.Get(__ctx__) != target.Get(__ctx__));
{
var __v__2 = new global::System.Activities.Statements.Sequence();
__v__2.Activities.Add(new Prompt().Initialize(__activity2__ =>
{
__activity2__.BookmarkName = new global::System.Activities.InArgument<string>(new global::MetahWFuncActivity<string>(__ctx__ => "EnterGuess"));
__activity2__.Text = new global::System.Activities.InArgument<string>(new global::MetahWFuncActivity<string>(__ctx__ => "Please enter a number between 1 and " + MaxNumber.Get(__ctx__)));
__activity2__.Result = new global::System.Activities.OutArgument<int>(new global::MetahWLocationActivity<int>(guess));
}
));
__v__2.Activities.Add(new global::MetahWActionActivity(__ctx__ =>
{
Turns.SetEx(__ctx__, __val__ => ++__val__, true);
}
));
var __v__3 = new global::System.Activities.Statements.If();
__v__3.Condition = new global::System.Activities.InArgument<bool>(new global::MetahWFuncActivity<bool>(__ctx__ => guess.Get(__ctx__) != target.Get(__ctx__)));
var __v__4 = new global::System.Activities.Statements.If();
__v__4.Condition = new global::System.Activities.InArgument<bool>(new global::MetahWFuncActivity<bool>(__ctx__ => guess.Get(__ctx__) < target.Get(__ctx__)));
__v__4.Then = new global::MetahWActionActivity(__ctx__ =>
{
Console.WriteLine("Your guess is too low.");
}
);
__v__4.Else = new global::MetahWActionActivity(__ctx__ =>
{
Console.WriteLine("Your guess is too high.");
}
);
__v__3.Then = __v__4;
__v__2.Activities.Add(__v__3);
__v__1.Body = __v__2;
}
__v__0.Activities.Add(__v__1);
__vroot__ = __v__0;
}
return __vroot__;
}
private global::System.Func<global::System.Activities.Activity> __implementation__;
protected override global::System.Func<global::System.Activities.Activity> Implementation
{
get
{
return __implementation__ ?? (__implementation__ = __GetImplementation__);
}
set
{
throw new global::System.NotSupportedException();
}
}
}
public sealed class Prompt : global::System.Activities.Activity<int>
{
public global::System.Activities.InArgument<string> BookmarkName { get; set; }
public global::System.Activities.InArgument<string> Text { get; set; }
private global::System.Activities.Activity __GetImplementation__()
{
global::System.Activities.Activity __vroot__;
var __v__0 = new global::System.Activities.Statements.Sequence();
__v__0.Activities.Add(new global::MetahWActionActivity(__ctx__ =>
{
Console.WriteLine(Text.Get(__ctx__));
}
));
__v__0.Activities.Add(new ReadInt().Initialize(__activity2__ =>
{
__activity2__.BookmarkName = new global::System.Activities.InArgument<string>(new global::MetahWFuncActivity<string>(__ctx__ => BookmarkName.Get(__ctx__)));
__activity2__.Result = new global::System.Activities.OutArgument<int>(new global::MetahWLocationActivity<int>(Result));
}
));
__vroot__ = __v__0;
return __vroot__;
}
private global::System.Func<global::System.Activities.Activity> __implementation__;
protected override global::System.Func<global::System.Activities.Activity> Implementation
{
get
{
return __implementation__ ?? (__implementation__ = __GetImplementation__);
}
set
{
throw new global::System.NotSupportedException();
}
}
}
}
这就是元编程,把语法糖解糖的过程,即把高级抽象的描述翻译成低级具体的实现。我觉得,“语法糖”是个肤浅的认识,实际上,多数的“语法糖”都涉及到语义,不仅仅是简单的语法转换。元编程的另一个例子,早期某些C++编译器能将C++代码翻译成等价的C代码,即C++是门元编程语言,它是C的“语法糖”。
日光之下,并无新事。元编程是个非常“古老”的概念,但在每个“时代”它都能玩出耳目一新的花样。
欲知后事如何,请听下回分解。
扩展C#与元编程(一)的更多相关文章
- 扩展C#与元编程
扩展C#与元编程 https://www.cnblogs.com/knat/p/4580393.html https://www.cnblogs.com/knat/p/4584023.html 扩展C ...
- 扩展C#与元编程(二)
如果你对Windows Workflow Foundation(WF)一无所知,当看到扩展C#与元编程(一)中由MW编译器生成的FirstLook.mw.cs时,也许这么在想:我KAO,这是C#版的汇 ...
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- atitit.元编程总结 o99
atitit.元编程总结 o99.doc 1. 元编程(Metaprogramming) 1 2. 元编程的历史and发展 1 3. 元类型and元数据 1 4. 元编程实现方式 2 4.1. 代码生 ...
- C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE
本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...
- effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
- Java元编程及其应用
首先,我们且不说元编程是什么,他能做什么.我们先来谈谈生产力. 同样是实现一个投票系统,一个是python程序员,基于django-framework,用了半小时就搭建了一个完整系统,另外一个是标准的 ...
- Java 元编程及其应用
Java 元编程及其应用 首先,我们且不说元编程是什么,他能做什么.我们先来谈谈生产力. 同样是实现一个投票系统,一个是python程序员,基于django-framework,用了半小时就搭建了一个 ...
- ES6中的元编程-Proxy & Reflect
前言 ES6已经出来好久了,但是工作中比较常用的只有let const声明,通过箭头函数改this指向,使用promise + async 解决异步编程,还有些数据类型方法...所以单独写一篇文章学习 ...
随机推荐
- mySQL 教程 第4章 数据查询
mySQL运算符 这些运算符在SQL查询中用得到. 算数运算符 + 加 - 减 * 乘 / DIV 除 % MOD 取余数 比较运算符 = 等于 <> != 不等于 < <= ...
- HttpFileCollection类
最近在学HttpRequest类搞文件上传的时候看到Request.Files返回了HttpFileCollection 这个类的一个对象,这个类用于获取浏览器上传的文件集合,在文件上传的时候可以通过 ...
- golang 自定义类型的排序sort
sort包中提供了很多排序算法,对自定义类型进行排序时,只需要实现sort的Interface即可,包括: func Len() int {... } func Swap(i, j int) {... ...
- springMVC学习(5)-参数绑定
接着上一集,记录参数绑定的过程: springmvc中,接收页面提交的数据是通过方法形参来接收: 一.默认支持的类型: 在controller形参中添加如下类型的参数处理适配器会默认识别并进行赋值: ...
- Java设计原则之里氏替换原则
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出.其严格表述如下:如果对每一个类型为S的 ...
- Spring Cloud config之二:功能介绍
SVN配置仓库 示例见:http://lvdccyb.iteye.com/blog/2282407 本地仓库 本地文件系统 使用本地加载配置文件.需要配置:spring.cloud.config.se ...
- [转载] ./configure,make,make install的作用
1.configure,这一步一般用来生成 Makefile,为下一步的编译做准备,你可以通过在 configure 后加上参数来对安装进行控制,比如代码:./configure –prefix=/u ...
- sklearn中的metrics模块中的Classification metrics
metrics是sklearn用来做模型评估的重要模块,提供了各种评估度量,现在自己整理如下: 一.通用的用法:Common cases: predefined values 1.1 sklearn官 ...
- spark1.0属性配置以及spark-submit简单使用
在spark1.0中属性支持三种配置方式: 1.代码 在代码中构造SparkConf时指定master.appname或者key-value等 val conf = new SparkConf(); ...
- python3 string
字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello World!' var2 ...