• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

扩展C#与元编程(一)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

众所周知,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 Promptas 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的“语法糖”。
日光之下,并无新事。元编程是个非常“古老”的概念,但在每个“时代”它都能玩出耳目一新的花样。
欲知后事如何,请听下回分解。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C#工具类之日期扩展类发布时间:2022-07-13
下一篇:
[C#基础]c#中的BeginInvoke和EndEndInvoke发布时间:2022-07-13
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap