从Atlas到Microsoft ASP.NET AJAX(3) - Class and Type Definition, Reflection APIs
2006-10-21 15:00 Jeffrey Zhao 阅读(3542) 评论(15) 编辑 收藏 举报
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版本中接口的定义方式:
在RTM版本中接口的定义方式和上面很相似,但是使用了在构造函数中抛出“强类型”异常的方式来避免实例化一个接口对象。在这里,我们并不会定义抽象方法,也不会定义具体实现。在Release状态下,接口不会有任何的代码或者成员定义。
当您在定义一个类型时使用接口,能够使用类似“反射”的API来测试这些类型。当您在实现接口时,您为自己对象的prototype添加接口中的成员实现,这一点和CTP版本中在类的构造函数中添加成员定义不同。
Enums and Flags
这部分的示例表现了在CTP版本和RTM版本中开发人员创建枚举(Enum)和标记(Flag)的区别。下面的示例展示了在CTP版本中创建枚举的方式:
在RTM版本中定义枚举和标记使用了类似的概念,而且增加可用性,并且能够为它添加文档注释。
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元素事件的绑定。示例如下:
这个例子也展示了使用attachEvent来相应DOM元素click事件的模型。这和IE的模型非常接近。
在代码中使用自己的handler响应客户端对象事件,会使用如下类似的方式:
由于多种原因,这个设计在RTM版本中被改变了。例如为了改善性能,提供和.NET Framework相似的编程模型,遵循ECMAScript标准和基于用户反馈等等。在RTM版本中,您能简单地使用命名规则来定义事件,这和属性的定义有些相似,使用了“add_”和“remove_”方法。工具也能识别出这种命名方式,例如这样就能够在IntelliSense中得到事件的提示了。
在高级的组件中,你能简单地将事件handler加到内置的EventHandlerList对象中,该对象可以使用Compoennt基类的get_events()方法获得。和CTP版本不同的是,RTM版本只在添加事件handler的时候构造事件对象,而不是在构造对象实例时就初始化了所有的事件对象。下面的示例展示了在RTM版本中定义事件的模型:
这个设计使得对象在需要时才会创建事件对象,它使用了一个新的类“DomEvent”的静态方法来添加或删除绑定在DOM元素上的事件,这是一个标准模型。在这个模型之下,一组抽象的API会提供对于浏览器兼容的支持。
如果需要将自己的handler绑定到事件上,您现在可以使用类似于下面的代码。参数sender是可选的,它能让你获得有关事件的更多信息,例如您可以确定是哪个Button被点击了。
在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");
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(); }
}
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版本中在类的构造函数中添加成员定义不同。
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");
/// <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(this, this._onClick);
this.element.attachEvent('onclick', _clickHandler);
}
this._onClick = function() {
this.click.invoke(this, Sys.EventArgs.Empty);
...
}
}
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(this, this._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() {
...
}
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(this, this._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);
}
}
}
initialize: function() {
Custom.Button.callBaseMethod(this, 'initialize');
this._handler =
Function.createDelegate(this, this._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);
}
}
}
这个设计使得对象在需要时才会创建事件对象,它使用了一个新的类“DomEvent”的静态方法来添加或删除绑定在DOM元素上的事件,这是一个标准模型。在这个模型之下,一组抽象的API会提供对于浏览器兼容的支持。
如果需要将自己的handler绑定到事件上,您现在可以使用类似于下面的代码。参数sender是可选的,它能让你获得有关事件的更多信息,例如您可以确定是哪个Button被点击了。
var b = new Custom.Button();
b.add_click(OnClickHandler);
function OnClickHandler(sender, args) {
..
}
b.add_click(OnClickHandler);
function OnClickHandler(sender, args) {
..
}