Hello World
Spiga

从Atlas到Microsoft ASP.NET AJAX(3) - Class and Type Definition, Reflection APIs

2006-10-21 15:00 by 老赵, 4055 visits
Class and Type Definition, Reflection APIs

在CTP版本中,您能创建各种各样的类型,例如类,接口,枚举和标记(flag)。这些功能在RTM版本中被改变了。

Abstract and Sealed Classes

在CTP版本中,您能够创建抽象类(abstract class)和密封类(sealed class)。在RTM版本中由于使用上原因,并且希望改进性能,我们去除了抽象类和密封类的概念,这使我们能够大大减少类库中的脚本数量、复杂性以及实现这些功能所代来的性能影响。

您在RTM版本中依旧能够使用register*形式的API定义命名空间、类和接口,但是它们从CTP版本中的Function.prototype转移到了RTM版本中的Type.prototype上。这对您的时候不会造成什么影响,因为在RTM版本中,我们将window.Type属性作为了Function的别名。尽管Function.*和Type.*都能够被正常使用,我们还是为此改变了推荐的使用方法。

我们在Type.prototype中定义了各种有关类型的API和基于“反射”的API,以提供一个牢固并逻辑性很强的设计模式。


Creating Types: Single and Multiple Inheritance

和CTP版本一样,RTM版本在开发时,能够继承一个类并且实现多个接口。在CTP版本中,您能定义一个有多个父类的类型,然而在RTM版本中,您只能使用单继承。

Interfaces

接口的定义方式在RTM版本中被改变了,新的定义方式使用了prototype模型,并且移除了对于抽象类的使用。下面的例子展示了在CTP版本中接口的定义方式:
Custom.ICustomContract = function() {
    
this.get_member = Function.abstractMethod;
    
this.getAnotherMember = Function.abstractMethod;
}
Custom.ICustomContract.registerInterface(
"Custom.ICustomContract");

在RTM版本中接口的定义方式和上面很相似,但是使用了在构造函数中抛出“强类型”异常的方式来避免实例化一个接口对象。在这里,我们并不会定义抽象方法,也不会定义具体实现。在Release状态下,接口不会有任何的代码或者成员定义。
Custom.ICustomContract = function() {
    
throw Error.notImplemented();
}
Custom.ICustomContract.registerInterface(
"Custom.ICustomContract");

Custom.ICustomContract.prototype 
= {
    get_member: 
function() { throw Error.notImplemented();},
    getAnotherMember: 
function() { throw Error.notImplemented(); } 
}

当您在定义一个类型时使用接口,能够使用类似“反射”的API来测试这些类型。当您在实现接口时,您为自己对象的prototype添加接口中的成员实现,这一点和CTP版本中在类的构造函数中添加成员定义不同。

Comment  这的确是一种正确的做法。在使用以前的Atlas定义接口和抽象类时可以发现,即使不定义抽象的成员,也能正常工作。如果在产品环境下保留这些代码只是一种浪费。在Microsoft ASP.NET AJAX的Client FX中,提供了一种“标准”以供接口和抽象类遵循,这是一个改进。
另外,文档中没有提到抽象类的定义方法——其实和定一个接口很相似,只是提供部分成员的实现而已。这就基本上使所谓“抽象”类和普通类几乎没有任何区别了,大概也就是因为这样,Client FX去除了所谓的“抽象类”吧。


Enums and Flags

这部分的示例表现了在CTP版本和RTM版本中开发人员创建枚举(Enum)和标记(Flag)的区别。下面的示例展示了在CTP版本中创建枚举的方式:
Type.createEnum("MyEnum""One"1"two"2);

在RTM版本中定义枚举和标记使用了类似的概念,而且增加可用性,并且能够为它添加文档注释。
MyEnum = function() {
   
/// <summary>..</summary>
}
MyEnum.prototype 
= {
  One: 
1,
  Two: 
2
}
MyEnum.registerEnum(
"MyEnum");


Properties, Methods, and Events

在CTP版本中,属性模型的定义是使用“get_”和“set_”来提供get和set方法来表示一个成员。这个模型在RTM版本中依旧保留,只是就像之前所提到的一样,这些方法被转移到了类型的prototype里,而不是使用closure的方式提供定义。

类似地,方法也使用了prototype进行定义。

在Client FX中存在着两种事件:ASP.NET AJAX客户端对象事件和DOM元素上的事件。Atlas的客户端对象将DOM事件封装在自己的事件中,以此为页面开发人员提供新的使用方式。从下面的示例里可能看到这一点:组件将DOM元素的click事件进行了封装,而直接将自己的click事件暴露在对象实例中。

在CTP版本中,客户端对象的事件被作为一个类的成员变量,在构造函数中被定义。页面开发人员能够响应这些对象的事件,在DOM元素的事件被触发时,对象的事件就会被触发。客户端对象在初始化(见示例)时将自己的handler绑定到DOM元素的事件上。因此,也需要在dispose方法中取消对DOM元素事件的绑定。示例如下:
Custom.Button = function(...) {
    
this.click = this.createEvent();

    
this.dispose = function() {
        
if (_clickHandler) {
            
this.element.detachEvent('onclick', _clickHandler);
            _clickHandler 
= null;
        }
        
        Custom.Button.callBaseMethod(
this, 'dispose');
    }
    
    
this.initialize = function() {
        Custom.Button.callBaseMethod(
this, 'initialize');
        
        _clickHandler 
= Function.createDelegate(thisthis._onClick);
        
this.element.attachEvent('onclick', _clickHandler);
    }
    
    
this._onClick = function() {
        
this.click.invoke(this, Sys.EventArgs.Empty);
        ...
    }
}

这个例子也展示了使用attachEvent来相应DOM元素click事件的模型。这和IE的模型非常接近。

在代码中使用自己的handler响应客户端对象事件,会使用如下类似的方式:
// Simple global handler.
var b = new Custom.Button();
b.click.add(OnClickHandler);
function OnClickHandler() {
    ...
}

由于多种原因,这个设计在RTM版本中被改变了。例如为了改善性能,提供和.NET Framework相似的编程模型,遵循ECMAScript标准和基于用户反馈等等。在RTM版本中,您能简单地使用命名规则来定义事件,这和属性的定义有些相似,使用了“add_”和“remove_”方法。工具也能识别出这种命名方式,例如这样就能够在IntelliSense中得到事件的提示了。

在高级的组件中,你能简单地将事件handler加到内置的EventHandlerList对象中,该对象可以使用Compoennt基类的get_events()方法获得。和CTP版本不同的是,RTM版本只在添加事件handler的时候构造事件对象,而不是在构造对象实例时就初始化了所有的事件对象。下面的示例展示了在RTM版本中定义事件的模型:
Custom.Button.prototype = {
    initialize: 
function() {
        Custom.Button.callBaseMethod(
this, 'initialize');
        
this._handler = 
            Function.createDelegate(
thisthis._onClickHandler);
        $addHandler(
this.get_element(), 'click', this._handler);
        ..
    }
    add_click: 
function(handler) {
        
this.get_events().addHandler('click', handler);
    },
    remove_click: 
function(handler) {
        
this.get_events().removeHandler('click', handler);
    },
    dispose: 
function() {
        
// Potential for dispose to be called more than once
        if (this._handler) {
            $removeHandler(
this.get_element(), 'click', this._handler);
            
delete this._handler;
        }
        Custom.Button.callBaseMethod(
this, 'dispose');
    },
    _onClickHandler: 
function() {
        
var ev = this.get_events().getHandler(this._handler);
        
if (ev) {
            ev (
this, Sys.EventArgs.Empty);
        }
    }
}

Comment  似乎Microsoft ASP.NET AJAX的确在性能和编程模型上作了很大努力,这从事件模型的改变上就能看出来。可以发现,“EventHanderList”对象的使用,与.NET Framework里为一个类定义大量事件时所用的Practice如出一辙。

   这个设计使得对象在需要时才会创建事件对象,它使用了一个新的类“DomEvent”的静态方法来添加或删除绑定在DOM元素上的事件,这是一个标准模型。在这个模型之下,一组抽象的API会提供对于浏览器兼容的支持。

如果需要将自己的handler绑定到事件上,您现在可以使用类似于下面的代码。参数sender是可选的,它能让你获得有关事件的更多信息,例如您可以确定是哪个Button被点击了。
var b = new Custom.Button();
b.add_click(OnClickHandler);
function OnClickHandler(sender, args) {
    ..
}

Comment  最后的代码的参数和说明我做了一点修改,个人认为文档上出现里一点错误。 

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

15 条回复

  1. aspnetx
    *.*.*.*
    链接

    aspnetx 2006-10-21 15:08:00

    老照的速度真是快啊

  2. 老赵
    admin
    链接

    老赵 2006-10-21 15:10:00

    @aspnetx
    我想抓紧时间在这个周末先熟悉一下……

  3. aspnetx
    *.*.*.*
    链接

    aspnetx 2006-10-21 16:08:00

    @Jeffrey Zhao
    继续关注你的系列

  4. 老赵
    admin
    链接

    老赵 2006-10-21 16:17:00

    @aspnetx
    谢谢阿。只是我估计“深入Atlas系列”不太会继续下去了,我看了看我写过的这部分内容的实现,还是有一定改变的。要写的话,也必须等我重新研究过这些以后再写了……

  5. aspnetx
    *.*.*.*
    链接

    aspnetx 2006-10-21 16:56:00

    @Jeffrey Zhao
    微软多少还是忽悠了咱们很多的技术人员
    不过,我始终觉得
    对于咱们
    只要不放弃,始终是对的

  6. 老赵
    admin
    链接

    老赵 2006-10-21 17:25:00

    @aspnetx
    是啊,忽悠了不止我们,还有技术作家和出版商……
    这次有点过分,不过估计Atlas开发组也下非常大的决心,否则不会改得那么彻底……

  7. 小蜗牛
    *.*.*.*
    链接

    小蜗牛 2006-10-21 17:32:00

    我想也是恩。

  8. lai[未注册用户]
    *.*.*.*
    链接

    lai[未注册用户] 2006-10-26 13:27:00

    good job

  9. 老赵
    admin
    链接

    老赵 2006-10-26 13:51:00

    thanks。:)

  10. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2006-12-04 20:41:00

    其实MS早就应该这么实现类层次结构了

    给写一个类集成接口的小例子吧,就用你上面的接口例子。
    attachEvent方法是每个DOM元素的标准方法吗?
    你说的是在什么IDE工具里支持js的IntelliSense功能呀
    ----------
    还是你这个系列好,大多我都能看懂,这个系列循序渐近,我的JS知识正好能跟的上。

  11. 老赵
    admin
    链接

    老赵 2006-12-04 20:47:00

    @蛙蛙池塘
    ASP.NET AJAX Library已经没有“接口”这个概念了,因为对于JS来说,它不需要。attachEvent是IE特有的方法,不是Web标准。这篇文章里提到的对于ASP.NET AJAX Library有良好IntelliSense支持的IDE是Ocras,就是下一代的Visual Studio。
    // 这个系列其实是官方白皮书的翻译,是我当时用来快速入门ASP.NET AJAX的。:)

  12. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2006-12-04 20:54:00

    我晕,那说了半天,现在还不支持呗。

  13. 老赵
    admin
    链接

    老赵 2006-12-04 22:25:00

    @蛙蛙池塘
    不是一直在说“会在下一代VS中得到支持”……

  14. 赵胖子真是喜欢你~~[未注册用户]
    *.*.*.*
    链接

    赵胖子真是喜欢你~~[未注册用户] 2007-05-06 03:20:00

    不建议我怎么叫你吧~!!
    做个程序员能吃胖是件很光荣的事
    我太喜欢的你代码内容了
    不用看字那么辛苦
    直接看代码就行了

  15. 老赵
    admin
    链接

    老赵 2007-05-06 05:20:00

    @赵胖子真是喜欢你~~
    唉,愁啊。我真是喝水也长肉,我休息的不多吃饭也注意就是瘦不了,还是要锻炼啊……

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我