阅读内容 

[集成IronPython] 使CLR对象对动态语言更友好(一)——

[日期:2008-08-19] 来源:  作者: [字体: ]
     支持运行时添加删除属性 动态类型语言(以下简称:"动态语言"),在10年前就已流行起来。JavaScript更是成为了WEB前台开发的事实标准。但它们进入普通开发 人员的视野也就在近几年。随着Web2.0和敏捷开发方法论的兴起,动态语言的灵活高效的特性成为了它被更多项目选择和使用的理由。一些大型网站已开始使 用动态语言来实现,其中,国内比较优秀的作品有“豆瓣”。微软更是不甘落后,建立了DLR(动态语言运行时)来吸引动态语言爱好者在其上实现动态语言。IronPython就是其主要成员之一。
  
  在本系列文章中,我们将逐步实现一个自定义控件,实现类似IDE的Immediate窗口的功能。用户可以在其中输入和运行IronPython代码。 【返回目录】
  
  
  --------------------------------------------------------------------------------
  
  在上一节中, 实现自定义模块的尝试失败了。后来仔细想想,也许有了clr module,以及IronPython在CLR对象的封装上实现了很多对IronPython兼容特性(呵呵,我想这个就可以做一个专题讨论)。我们大多时候已经可以将CLR对象当作IronPython对象一样操作了。也许这就是为什么IronPython不打算将PythonModuleAttribute提供给我们用的原因。谁知道呢,也许微软提供了途径,我没有找到。
  
  
  IronPython在对CLR对象进行封装时,已经进行了很多兼容方面的考虑。但是,有些东西,IronPython仅仅提供了方案。真正的实现还是要我们自己来了。
  
  比如:让一个CLR对象支持动态类型。即运行时添加删除属性和方法。
  
  
  大家知道,对于静态类型语言,一个对象的类型在它被创建时就被确定下来,并且不能被改变。而一个类型具有哪些成员也是在编译时被确定下来的。因此,下面的代码在编译时就会报错。
  
  
   1public class Foo
   2{
   3 public int Bar { get; set; }
   4
   5 public static void Main()
   6 {
   7 Foo foo = new Foo();
   8 foo.xxx = 10; // 这一行编译失败
   9 }
  10}
  
  而对于动态类型语言,类似上面的代码就完全是合法的代码。对于大多数习惯了C#这样的强类型语言的开发人员(包括我自己)可能都觉得这样的规定除了增加出错概率外,没有任何意义。但是,这样的规定配合一些其它功能(比较有名的就是鸭子接口),这样的设计反而可以发挥出来巨大的优势。好的,我们不来讨论哪种语言更好,仅仅给出上面代码的IronPython版本。
  
  1class Foo:
  2 Bar = 0
  3
  4foo = Foo()
  5foo.xxx = 10
  呵呵,Python确实比C#精炼
  
  如果使用我们的DLConsole,你会发现对于我们植入的对象(比如:Button1和TextBox1),下面的代码就会产生一个MissingMemberException('Button' object has no attribute 'xxx')。
  
  
  Button1.xxx = 10
  先让我们从头开始实现一个类型,让你可以在其中添加和删除成员。代码如下:
  
   1 public class DLRFriendlyObject
   2 {
   3 Dictionary<string, object> _dict = new Dictionary<string, object>();
   4
   5 // 呵呵,这个属性就永远都不能被IronPython访问了。
   6 public string Foo { get { return "this should not be returned"; } }
   7
   8 [SpecialName]
   9 public object GetCustomMember(string name)
  10 {
  11 if (name == "_dict")
  12 return _dict;
  13 else
  14 return _dict[name];
  15 }
  16
  17 [SpecialName]
  18 public void SetMember(string name, object value)
  19 {
  20 _dict[name] = value;
  21 }
  22
  23 [SpecialName]
  24 public void DeleteMember(string name)
  25 {
  26 _dict.Remove(name);
  27 }
  28
  29 [SpecialName]
  30 public IEnumerable<string> GetMemberNames()
  31 {
  32 return _dict.Keys;
  33 }
  34 }
  注:因为这个类型和DLConsole没有直接关系,因此,上面的代码在TestDynamicLanguageConsole工程中。
  
  上面的代码中,出现了一个比较特别的Attribute [SpecialName],它被定义在“System.Runtime.CompilerServices”命名空间下,也就是说,它并不是DLR定义的Attribute。查了一下MSDN,发现“.NET Framework 中目前不使用 SpecialNameAttribute 类,但该类被保留以备将来之用。”。呵呵,看来微软早就留了一手。
  
  这一节中添加的几个Special的方法,都添加了这个Attribute。你会发现,随后的几节中,你随时都会发现这个Attribute的身影。如果你不添加这个Attribute,IronPython都会将它们当作普通成员处理。
  
  
  除此之外,就是四个固定名称的方法:GetCustomMember, SetMember, DeleteMember和GetMemberNames。实现这些方法,使用一个标准的Dictionary储存这些属性就可以了。现在,你就可以在IronPython中象操作动态类型对象一样的操作这个对象了。
  
  
  为了简单,我的演示程序中直接将该对象注册到Scope中了。你可以使用第二讲中的方法,通过clr模块从头构建这个对象。
  
  下面是运行效果图
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  
  
  但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。
  
  现在,你已经可以实现一个对IronPython“脸熟”的类型了。但是,对于系统已经定义的类型怎么办呢?也许你会说采用继承的方式,增加这几个Special方法。但是,很多时候,这样很难做到,比如:类型是Sealed的或者类型的创建不由你控制等。怎么办呢?
  
  下一节,我们将会不通过继承,让已有CLR类型对IronPython“脸熟”。敬请关注
  
  大家可以从这里下载可运行的源代码。
  http://www.cnblogs.com/Cajon/archive/2008/07/19/integrate_ironpython_into_winform_downloads.HTML  
阅读:
录入:blue1000

推荐 】 【 打印
相关新闻      
本文评论       全部评论
发表评论
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款


点评: 字数
姓名:
Advertisement
内容查询


Advertisement