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


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(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() {
  ...
}

  由于多种原因,这个设计在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);
    }
  }
}


  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  最后的代码的参数和说明我做了一点修改,个人认为文档上出现里一点错误

本文作者:
« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3