posts - 17, comments - 1, trackbacks - 0, articles - 1

2008年7月18日


我们将借用一个非常经典的例子:鸭子模拟程序[1]。如下图所示,我们的程序需要表现Mallard Duck(绿头野鸭)、Redhead Duck(红头野鸭)和Rubber Duck(橡皮鸭子)。由于Mallard Duck和Redhead Duck都有一个相同的函数“Fly()”,所以我们把这个函数提升到了父类Duck中。


由于Rubber Duck是Duck的子类,所以它自动获得了Fly()这个函数,但是橡皮鸭子是不能飞的!这是一个十分常见的设计问题。我们经常会把一些相关的类组织在一起,将它们共有的行为提升到父类中。这样做的好处不仅仅是少写了几行代码,更为重要的是,所有的子类拥有了相同的行为模式——对于新加入的开发者,他只要弄懂了父类,就对整个类层次了解了一大半;对于在程序的生命周期内需要不断增加子类的情况,这种设计就更加显得方便,因为我们不需要在每增加一个子类的时候都把所有的逻辑重新想一遍。
但是,讽刺的是,如果子类很多,就难免出现像Rubber Duck这样的另类;对于需要不断增加子类的情况,就更加的糟糕,我们在每一次将子类的行为提升到父类时都会恐惧将来会不会出现一个另类无法适用已经固定在父类中的逻辑……
下面将分别讨论可以解决此问题的4种不同的方法。

第1种设计:使用虚函数

最简单的方法就是把父类中的Fly()函数设为虚函数,并提供一个默认的实现。子类可以根据需要决定使用父类的默认实现或者重写一个新的实现,如下图所示。


嗯,这不是一个让人舒服的设计。那个Rubber Duck看起来就像一个转校生,它孤单寂寞,老师也不喜欢它。有时,你甚至会听到Duck、Mallard Duck和Redhead Duck在悄悄商量着:放学后我们去打电动游戏吧,嘘,别让Rubber Duck听到了……
如果需要不断的增加子类,情况就更加的糟糕。因为另类越来越多,我们只能尽力确保最初的那个小团体里的代码重用和逻辑一致。对于新来的,只能放任自流。
还有一个问题就是:对于那个不会飞的Rubber Duck,是否应该提供一个Fly()函数呢?有人赞成这样做,因为这样可以使用一个一致的接口来操作所有的Duck,例如可以这样写:
IList<Duck> ducks = new List<Duck>();
ducks.Add(
new MallardDuck());
ducks.Add(
new RedheadDuck());
ducks.Add(
new Rubber Duck());
foreach(Duck duck in ducks)
{
    duck.Fly();
}
也有人讨厌这样做。理由是,OO最吸引人的地方就是它是与人的思考方式最接近的编程方法。一个好的设计可以非常简洁自然,以至于不需要额外的文档加以说明。而Rubber Duck提供的Fly()函数无疑是一个例外情况,这样的例外越多,人们就越容易迷惑。就好像一个人的简历中明明写着“精通.net”,却既不懂C#,也不会VB,这么做只是为了和别人的简历一致,岂不是很奇怪?
那么,用窄接口会怎么样?
源代码下载:VirtualMethod.rar (VS2005控制台工程)
第2种设计:使用窄接口

如下图所示,在这个设计里提炼出了一个概念:Flyable。


请注意将一个概念显式地表现出来有多么的重要:现在我们都知道要实现哪些函数才算得上是“会飞”,并且知道Mallard Duck和Redhead Duck会飞,而Rubber Duck不会飞。
但是这个设计也有一个大缺点:Mallard Duck和Redhead Duck的Fly()是重复的代码,可是我们无法把它提升到Flyable接口中去,因为.net的接口里只允许定义抽象函数。与第1种设计相比,父类对子类控制的力度不够,增加子类也比较费事。
源代码下载:Interface.rar(VS2005控制台工程)
第3种设计:应用Strategy模式

这次,我们提炼出来的概念不再是“会不会飞(Flyable)”,而是“飞行的方式(FlyBehavior)”。


Duck的子类不再需要重复实现Fly()函数了,它们现在只需要指定一个适合自己的飞行方式就可以了。特别地,我们不再恐惧增加新的Duck的子类了——如果新的Duck的子类需要新的飞行方式,我们只要再增加一个FlyBehavior接口的实现类就可以了。这简直就是一个完美的设计!当然,看上去有些复杂,如果硬要挑出些毛病的话。
源代码下载: Strategy.rar(VS2005控制台工程)
第4种设计:使用Mixin

Mixin曾是Ruby等动态语言的独门秘技,没想到.net这个静态语言竟然也能学到八分像,还给取了个名叫Extension Methods。不过它绝不仅仅是“利用语法糖为无法修改源代码的类增加些函数”这么简单,它可以给我们更多的选择。还记得第2种设计(使用窄接口)的缺点么?没错,Mallard Duck和Redhead Duck的Fly()是重复的代码。Extension Methods正好可以用来解决这个问题。

注:我使用了一种比较形象的方法表示FlyModule和Flyable之间的关系,这并不是官方认可的UML表示法。
源代码下载: Mixin1.rar(VS2008控制台工程)
Strategy VS Mixin

现在来考虑为所有的Duck增加一个Quack()的功能。Mallard Duck和Redhead Duck可以嘎嘎叫(quack),而Rubber Duck只能吱吱叫(squeak)。Strategy和Mixin将如何应对这一需求变化呢?

1. Strategy



我们可以效仿FlyBehavior再添加一个QuackBehavior。虽然看上去需要作许多工作(添加了1个接口和2个类),但是可以注意到需要修改的代码非常少,大部分工作都是在新增代码(符合open-close原则);而且新增的代码只要按照原有的代码照猫画虎即可,基本不用怎么动脑子——这些正是优秀设计的特点。
源代码下载: Strategy2.rar(VS2005控制台工程)
2. Mixin



如上图所示,增加了Quackable和Squeakable两个接口,相当地简单直接。
源代码下载: Mixin2.rar(VS2008控制台工程)
Strategy和Mixin,你喜欢哪一个呢?

Strategy会使概念更集中一些——只要看一下Duck抽象类中都有哪些函数,对整个类层次就了解得差不多了;而且,FlyBehavior都有哪些实现方式也一目了然。统一的宽接口使得Client代码简单而一致。特别地,Strategy允许运行期动态更换FlyBehavior和QuackBehavior的实现,这是.net里的Mixin做不到的。

如果你是窄接口的拥护者,那么很可能会选Mixin了。不过看一下上面那个图,会有一种散和乱的感觉。Mixin更适合实现比较独立的概念,或是XXUtility这种东西。Mixin给人的感觉是简单、直接、轻巧。

Mixin 和 Template Method

Mixin非常适合用来实现“无论你是谁,只要提供了CompareTo()函数,就可以立即免费获得LessThan()、GreaterThan()、EqualTo()、LessEqual()和GreaterEqual() 这5个非常有用的函数”这样的语义。


Client代码:
IList<Duck> ducks = new List<Duck>();

MallardDuck duck1 
= new MallardDuck(1);
MallardDuck duck2 
= new MallardDuck(2);
MallardDuck duck3 
= new MallardDuck(2);

Console.WriteLine(
"duck1 <  duck2 ?   {0}", duck1.LessThan(duck2));
Console.WriteLine(
"duck1 >  duck2 ?   {0}", duck1.GreaterThan(duck2));
Console.WriteLine(
"duck1 <  duck3 ?   {0}", duck1.LessThan(duck3));
Console.WriteLine(
"duck2 <= duck3 ?   {0}", duck2.LessEqual(duck3));

源代码下载: Mixin3.rar(VS2008控制台工程)
以前,要想实现同样的语义只能用Abstract Class。


单以这个例子来看,使用Mixin有许多优点。首先,我们提炼出了一个明确、独立、通用的概念IComparable。其次,IComarable+CompareModule重用性更好。在这个例子中,由于IComarable+CompareModule里面的内容并不是领域相关的,所以就更应该将其提炼出来,这样Mallard Duck就可以集中精力处理领域相关的问题,程序的结构更加清晰,可读性更好。

不过上面那个例子并不能算得上是真正的Template Method模式。真正的Template Method模式是将所有子类共有的完成某项任务的算法提炼到父类中固定下来,子类只负责实现算法中的一个部分,不需要操心整个算法的所有步骤以及进行这些步骤的先后顺序和条件。就像说把大象装冰箱统共分三步,其实把猪装冰箱也统共分三步,把任何东西装冰箱都是分三步,这样我们就发现了一个可以提炼出来的算法“装冰箱”。

我们提炼出概念或算法不仅仅是为了“代码”重用——少些几行代码,仅仅是节省了一点儿体力而已。更为重要的是,我们想要节省脑力——对于已有代码,可以更快、更深刻地理解;如果需要新增代码,不需要把所有的逻辑再想一遍。

沏茶和泡咖啡的方法很相似,都要先烧水,然后把茶或速溶咖啡放入杯子,再倒满水。而且都需要考虑不少的细节,比如沏茶要用80度的水,泡咖啡用95度的最好;沏茶的话可以加两朵菊花,泡咖啡可以多加些糖;茶是可以直接加水续杯的,而咖啡不能续杯……如果有一天我想喝黑芝麻糊,难道必须再把所有的细节再想一遍?在现实生活中没有办法,但是在编程世界里就可以使用Template Method模式来逃避这烦人的工作。


活在编程世界是不是比现实世界要轻松些?

不过本文并不是想讲述Template Method的诸多好处,而是想问一个问题:用Mixin的方式代替Abstract Class实现Template Method模式是否更好?一个明显的好处是可以不受.net单继承的限制。

.net 只允许单继承,一个类只能继承一个Abstract Class,有时这的确挺不爽的。比如要实现一个“黑芝麻糊及刨冰一体机”,以前只能使用组合的方法。


而如果使用Mixin,就能使用多继承了。


等一等,多继承不是复杂与混乱之源么?是的,在C++中使用多继承确实存在许多陷阱和禁忌[3]。造成多继承复杂性的主要原因是属性和函数的模棱两可(ambiguity)问题——如果子类所继承的多个父类中有同名的函数或属性,当子类重载这些函数或Client代码想要调用这些函数时,编译器会不知道应当重载或调用哪个父类的函数。经过多年的实践和讨论,人们意识到必须对多继承做一些限制以减少造成混乱的可能性。.net中的Interface+显式实现接口正是这样一个简单而优雅的折中方案。现在,.net又稍稍放宽了限制,允许使用Interface+Extension Methods的方式多继承非虚函数,使得.net中的多继承功能更强大了一些。

Template VS Freedom

你会害怕使用继承么?你是否曾对Template Method模式充满恐惧?我曾经觉得把子类的核心算法提升到父类中固定下来是一个疯狂的想法。继承会造成子类对父类强烈的依赖,特别是使用Template Method模式的时候,子类将受到父类强大的束缚。我不喜欢束缚,我喜欢自由。特别是我还铭记着“组合优于继承”的设计原则。于是我分离出了一个又一个XxxUtility和Xxxxxxer,于是我的Abstract Class成了空壳。后来,我突然发现每次增加子类都要把所有的实现步骤和细节全部重新想上一遍同样十分恐怖,特别是有50多个子类等着你去添加的时候。继承使得子类对父类产生很强的依赖,这可以看作是缺点,但是也可以说,父类对子类有很强的“控制力”(特别是在使用Template Method模式的时候),使得子类简单而又整齐划一,就像同一个模子里铸出来的锡兵一样。幸运的是,继承和组合并不是一个非此即彼的抉择,我们可以在纪律和自由之间折中。把子类的核心算法提升到父类中形成Template Method模式,把其它的重复代码提炼出来形成Strategy或Mixin再使用之。不用害怕,没有人可以在一开始设计的时候就做出完美的提炼,除非他以前作过类似的程序或者是个不折不扣的先知。



参考文献

[1] Freeman et al, Head First Design Patterns. O’Reilly, 2004.
     影印版:深入浅出设计模式(英文影印版)。东南大学出版社,2005。

[2] Thomas et al, 孙勇等 译, Programming Ruby 中文版。电子工业出版社,2007.

[3] Meyers,侯捷 译, Effective C++ 中文版。华中科技大学出版社,2001. ——条款43:明智地运用多继承。

posted @ 2008-07-18 14:22 何睿 阅读(2) | 评论 (0)编辑

2008年6月25日

  html   =   text/html  
  htm   =   text/html  
  gif   =   image/gif  
  jpeg   =   image/jpeg  
  ps   =   application/postscript  
  shtml   =   text/x-server-parsed-html  
  jpg   =   image/jpeg  
  jpe   =   image/jpeg  
  mpeg   =   video/mpeg  
  mpe   =   video/mpeg  
  mpg   =   video/mpeg  
  bin   =   application/octet-stream  
  exe   =   application/octet-stream  
  Z   =   application/octet-stream  
  EXE   =   application/octet-stream  
  dll   =   application/octet-stream  
  DLL   =   application/octet-stream  
  ivsrv   =   application/octet-stream  
  pdf   =   application/pdf  
  au   =   audio/basic  
  snd   =   audio/basic  
  aiff   =   audio/x-aiff  
  aifc   =   audio/x-aiff  
  aif   =   audio/x-aiff  
  wav   =   audio/x-wav  
  ai   =   application/postscript  
  eps   =   application/postscript  
  rtf   =   application/rtf  
  zip   =   application/zip  
   
    ief   =   image/ief  
  tiff   =   image/tiff  
  tif   =   image/tiff  
  ras   =   image/x-cmu-raster  
  pnm   =   image/x-portable-anymap  
  pbm   =   image/x-portable-bitmap  
  pgm   =   image/x-portable-graymap  
  ppm   =   image/x-portable-pixmap  
  rgb   =   image/x-rgb  
  xbm   =   image/x-xbitmap  
  xpm   =   image/x-xpixmap  
  xwd   =   image/x-xwindowdump  
  txt   =   text/plain  
  rtx   =   text/richtext  
  tsv   =   text/tab-separated-values  
  etx   =   text/x-setext  
  qt   =   video/quicktime  
  mov   =   video/quicktime  
  avi   =   video/x-msvideo  
  movie   =   video/x-sgi-movie  
  js   =   application/x-javascript  
  ls   =   application/x-javascript  
  mocha   =   application/x-javascript  
  wrl   =   x-world/x-vrml  
  dir   =   application/x-director  
  dxr   =   application/x-director  
  dcr   =   application/x-director  
  crt   =   application/x-x509-ca-cert  
  tar   =   application/x-tar  

posted @ 2008-06-25 09:59 何睿 阅读(27) | 评论 (0)编辑

2008年5月21日

在默认情况下,SelectParameter类型不能为GUID类型,如果用Object类型代替,会出现如下错误


Operator '==' incompatible with operand types 'Guid' and 'String'

说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.Web.Query.Dynamic.ParseException: Operator '==' incompatible with operand types 'Guid' and 'String'


解决办法是

    <asp:LinqDataSource ID="LinqDataSource1" runat="server" 

        ContextTypeName
="DBDataContext" OrderBy="RequestDate desc" 

        TableName
="ApplicationResultsViews" Where="ApplicantID == Guid(@ApplicantID)">

        
<WhereParameters>

            
<asp:Parameter Name="ApplicantID" Type="String"/>

        
</WhereParameters>

    
</asp:LinqDataSource>


希望对遇到同样问题的朋友有帮助

posted @ 2008-05-21 10:30 何睿 阅读(55) | 评论 (0)编辑

2008年4月25日

以下文章来自博客园,觉得比较好,就转载过来了,,,大家看下

基本原则 

  • 封装变化Encapsulate what varies.
  • 面向接口变成而不是实现 Code to an interface rather than to an implementation.
  • 优先使用组合而非继承 Favor Composition Over Inheritance

SRP: The single responsibility principle 单一职责

系统中的每一个对象都应该只有一个单独的职责,而所有对象所关注的就是自身职责的完成。

Every object in your system should have a single responsibility ,and all the object s services should  be focused on carrying out that single responsibility .

 

  1. 每一个职责都是一个设计的变因,需求变化的时候,需求变化反映为类职责的变化。当你系统里面的对象都只有一个变化的原因的时候,你就已经很好的遵循了SRP原则。
  2. 如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个职责的变化就可能削弱或者抑制这个类其它职责的能力。这种设计会导致脆弱的设计。当变化发生的时候,设计会遭到意想不到的破坏。
  3. SRP 让这个系统更容易管理维护,因为不是所有的问题都搅在一起。
  4. 内聚Cohesion 其实是SRP原则的另外一个名字.你写了高内聚的软件其实就是说你很好的应用了SRP原则。
  5. 怎么判断一个职责是不是一个对象的呢?你试着让这个对象自己来完成这个职责,比如:“书自己阅读内容”,阅读的职责显然不是书自己的。
  6. 仅当变化发生时,变化的轴线才具有实际的意义,如果没有征兆,那么应用SRP或者任何其它的原则都是不明智的。

DRY : Don't repeat yourself Principle

通过抽取公共部分放置在一个地方避免代码重复.

Avoid duplicate code by abstracting out things that are common and placing those thing in a single location .

 

  1. DRY 很简单,但却是确保我们代码容易维护和复用的关键。
  2. 你尽力避免重复代码候实际上在做一件什么事情呢?是在确保每一个需求和功能在你的系统中只实现一次,否则就存在浪费!系统用例不存在交集,所以我们的代码更不应该重复,从这个角度看DRY可就不只是在说代码了。
  3. DRY 关注的是系统内的信息和行为都放在一个单一的,明显的位置。就像你可以猜到正则表达式在.net中的位置一样,因为合理所以可以猜到。
  4. DRY 原则:如何对系统职能进行良好的分割!职责清晰的界限一定程度上保证了代码的单一性。

OCP : Open-Close Principle开闭原则

类应该对修改关闭,对扩展打开;

Classes should be open for extension ,and closed  for modification .

 

  1. OCP 关注的是灵活性,改动是通过增加代码进行的,而不是改动现有的代码;
  2. OCP的应用限定在可能会发生的变化上,通过创建抽象来隔离以后发生的同类变化
  3. OCP原则传递出来这样一个思想:一旦你写出来了可以工作的代码,就要努力保证这段代码一直可以工作。这可以说是一个底线。稍微提高一点要求,一旦我们的代码质量到了一个水平,我们要尽最大努力保证代码质量不回退。这样的要求使我们面对一个问题的时候不会使用凑活的方法来解决,或者说是放任自流的方式来解决一个问题;比如代码添加了无数对特定数据的处理,特化的代码越来越多,代码意图开始含混不清,开始退化。
  4. OCP 背后的机制:封装和抽象;封闭是建立在抽象基础上的,使用抽象获得显示的封闭;继承是OCP最简单的例子。除了子类化和方法重载我们还有一些更优雅的方法来实现比如组合;

怎样在不改变源代码(关闭修改)的情况下更改它的行为呢?答案就是抽象,OCP背后的机制就是抽象和多态

  1. 没有一个可以适应所有情况的贴切的模型!一定会有变化,不可能完全封闭.对程序中的每一个部分都肆意的抽象不是一个好主意,正确的做法是开发人员仅仅对频繁变化的部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。
  2. OCPOOD很多说法的核心,如果这个原则有效应用,我们就可以获更强的可维护性 可重用 灵活性 健壮性 LSPOCP成为可能的主要原则之一

LSP: The Liskov substitution principle

子类必须能够替换基类。

Subtypes must be substitutable  for their base types.

 

  1. LSP关注的是怎样良好的使用继承.
  2. 必须要清楚是使用一个Method还是要扩展它,但是绝对不是改变它。
  3. LSP清晰的指出,OODIS-A关系是就行为方式而言,行为方式是可以进行合理假设的,是客户程序所依赖的。
  4. LSP让我们得出一个重要的结论:一个模型如果孤立的看,并不具有真正意义的有效性。模型的有效性只能通过它的客户程序来表现。必须根据设计的使用者做出的合理假设来审视它。而假设是难以预测的,直到设计臭味出现的时候才处理它们。
  5. 对于LSP的违反也潜在的违反了OCP

DIP:依赖倒置原则

高层模块不应该依赖于底层模块 二者都应该依赖于抽象

抽象不应该依赖于细节 细节应该依赖于抽象

  1. 什么是高层模块?高层模块包含了应用程序中重要的策略选择和业务模型。这些高层模块使其所在的应用程序区别于其它。
  2. 如果高层模块依赖于底层模块,那么在不同的上下文中重用高层模块就会变得十分困难。然而,如果高层模块独立于底层模块,那么高层模块就可以非常容易的被重用。该原则就是框架设计的核心原则。
  3. 这里的倒置不仅仅是依赖关系的倒置也是接口所有权的倒置。应用了DIP我们会发现往往是客户拥有抽象的接口,而服务者从这些抽象接口派生。
  4. 这就是著名的Hollywood原则:"Don't call us we'll call you."底层模块实现了在高层模块声明并被高层模块调用的接口。
  5. 通过倒置我们创建了更灵活 更持久更容易改变的结构
  6. DIP的简单的启发规则:依赖于抽象;这是一个简单的陈述,该规则建议不应该依赖于具体的类,也就是说程序汇总所有的依赖都应该种植于抽象类或者接口。
  7. 如果一个类很稳定,那么依赖于它不会造成伤害。然而我们自己的具体类大多是不稳定的,通过把他们隐藏在抽象接口后面可以隔离不稳定性。
  8. 依赖倒置可以应用于任何存在一个类向另一个类发送消息的地方
  9. 依赖倒置原则是实现许多面向对象技术多宣称的好处的基本底层机制,是面向对象的标志所在。

ISP:接口隔离原则

不应该强迫客户程序依赖它们不需要的使用的方法。

 

  1. 接口不是高内聚的,一个接口可以分成N组方法,那么这个接口就需要使用ISP处理一下。
  2. 接口的划分是由使用它的客户程序决定的,客户程序是分离的接口也应该是分离的。
  3. 一个接口中包含太多行为时候,导致它们的客户程序之间产生不正常的依赖关系,我们要做的就是分离接口,实现解耦。
  4. 应用了ISP之后,客户程序看到的是多个内聚的接口。

posted @ 2008-04-25 09:48 何睿| 编辑

2008年4月22日

今天使用fiddler的时候出现如下问题:
[Fiddler] Connection to localhost. failed.
Exception Text: 由于目标机器积极拒绝,无法连接。 ::
1:1280 
在网上找了一圈,先后发现如下几个解决方案:
Fiddler and Visual Studio built-in web server
大意是要让支持所有协议,试过后不奏效
然后又发现最常见的加“.”解决方案
[Note] - Fiddler localhost
仍然不奏效,
最后在 Using Fiddler with ASP.NET's default local server 一文的回复中找到了答案
To solve the error:

[Fiddler] Connection to localhost. failed.

Exception Text: No connection could be made because the target machine actively refused it

Tools 
-> Fiddler Options -> remove 'enable IPv6'

呵呵,原来是因为自己机器上一直使用IPV6协议看高清视频的原因。希望有对有同样问题的朋友有帮助。



posted @ 2008-04-22 18:01 何睿 阅读(136) | 评论 (1)编辑

2008年4月17日

     摘要: 向页面加入Live.com搜索条的snippet  阅读全文

posted @ 2008-04-17 14:58 何睿 阅读(124) | 评论 (0)编辑

2008年3月24日

 

原帖见:
http://www.joelonsoftware.com/items/2008/03/17.html

中文翻译by modico @ smth:
http://www.newsmth.net/bbstcon.php?board=Java&gid=108485

火星人的耳机

你即将看到一场在互联网社区由Web开发人员挑起的可比为所有“口水战”之母的大规模争论。其规模之大,使得斯大林格勒战役看起来不过就像下午茶时间你的嫂子气冲冲从你的祖母家出去,将一匹难驯野马绑在树上罢了。

这场口水战的领头人物是微软老兵Dean Hachamovi,他正主持开发IE下一版本8.0IE 8.0的开发团队目前正要做出一个决定,在两种不同世界观的中间断层线上做决定。这是保守者和自由主义者,理想主义者和现实主义者的分歧。这是一场对同一家族中的所有成员分门别类的圣战,Web工程师vs 计算机科学家,Lexus vs 橄榄树[1]

目前没有解决办法,但这场争论确实很适合用娱乐的眼光去看待,因为其中参与者99%并不打算去理解他们在讨论什么。但又不止是娱乐:对于每个设计互操作系统的开发人员这又是必读的。

这场争论的焦点是颁布所谓的“Web标准”,让Dean来介绍这个问题

所有的浏览器有一个“标准”模式,用来让浏览器最好的执行Web标准,因为每种浏览器的每个版本都在提升对Web标准的支持。诸如Safari 3的标准模式,Firefox 2的标准模式,IE6的标准模式,IE7的标准模式,并且它们都不一样。我们想使IE8比IE7的标准模式更加的,更加的好。

当IE8碰到许多虽宣称支持“标准”,但仅仅在IE7上边通过测试的网页的时候,整个问题的关键就在于IE8做出的这个微不足道的决定上边。

什么是该死的标准?

不是所有的工程都有标准么?是的都有。

它们通常不都起着作用么?(这个……)

为什么“Web标准”造成这些该死的混乱?(不只是微软的错,也是你本人的错,和Jon Postel的错,一会再解释。)

没有解决办法。每种解决办法都是非常错误的。

Eric Bangemanars technica写道“IE团队在既要严格支持W3C标准又要确保现有针对早期版本IE开发的网站仍然正常显示的这条细钢丝绳上前行。这话不对。这不是一条细绳,这是一根负宽度的绳。没有落脚的地方,做什么与不做,同样遭恨。

这就是对此事件我不知道我该站在哪边的原因,我也不打算站在任何一边。但是每个当前的软件开发人员应该明白,至少,标准是如何起作用的,标准应该如何起作用,为什么我们会深陷这些混乱中,在此我想对这个问题做点解释,并且你会发现为什么Vista卖得如此惨淡,这同我之前文中提及的微软Raymond Chen阵营(实用主义者)和MSDN阵营(理想主义者)是同一回事。MSDN阵营到是赢了,它让现在人们都搞不清楚熟悉的菜单命令在Office 07’中都跑到哪儿去了,没人想装Vista。所有这些都是同一个辩题:你是理想主义者(红方)还是现实主义者(蓝方)。

就让我从头开始吧,从思考如何使一些东西一起协同的工作开始说起。

所说的一些东西是什么?随便,真的。铅笔和铅笔刀,电话和电讯系统,HTML网页和Web浏览器。Windows用户图形界面应用程序和Windows操作系统,Facebook和Facebook程序,立体声耳机和立体声。

在所有这些东西的结合部分上,要同意遵守多种规则,否则没法配合协同工作。

我举个简单的例子来说明。

假想你去了火星,你发现火星人没有便携音乐播放器,他们仍然使用大笨放音机。

意识到商机来了,你开始出售MP3(不过火星人管这玩艺儿叫Qxyzrhjjjjukltks)和适配的耳机。为了使耳机连到MP3上,你发明了精巧的金属插销,象这个样子:


    因为你控制着播放器和耳机,你能保证你的播放器与耳机相配。这是个一对一市场。一种播放器,一种耳机。
 

也许你详细写了一个规范,希望第三方会制造不同颜色的耳机,因为火星人很挑剔塞在他们耳朵里的东西的颜色。



在你写规范的时候,你忘了说明电压应该是1.4伏左右。你只是忘了。所以第一家积极的制造商生产的100%兼容的耳机问世了,他的喇叭只设计为0.014伏,当他测试原型的时候,要么爆掉耳机,要么震聋人的耳朵,看哪一件先发生。然后他做了些调整,逐渐地做好了一个好耳机,只是比你的稍微难看一点。

越来越多的制造商展示兼容耳机,不久我们处在了一个一对多的市场。

















到目前为止,情况还不错。我们有了一个耳机插头的事实标准。那个写好的规范并不完整,也不适当。但是任何想要生产兼容耳机的人都可以把耳机插头插到你的播放器里去测试,如果配合良好,一切都好,他们可以卖了,而且肯定可以用。

直到你决定搞个新版本,Qxyzrhjjjjukltk 2.0。

Qxyzrhjjjjukltk 2.0将附带一个电话(说明火星人也不能设计他们自己的手机),耳机将有一个内置的麦克风,这要求多一段触头,因此你重做了一个完全不兼容的插头,样子难看,有各种各样的扩展口:

 

Qxyzrhjjjjukltk 2.0在市场上完败。是的,它有非常不错的电话功能,但是没人在乎它。他们在乎的是自己大量的耳机收藏。我之前说火星人很挑剔塞在他们耳朵里的耳机,不是玩笑。大多数时尚的火星人在此刻有一整柜子各种各样漂亮的耳机。他们在你看来都一样(红色的),但火星人就是非常非常讲究红色的那种细微变化,这是你所永远无法想象的。最新的火星高级公寓都要标榜自己有一个耳机柜。我不骗你。

我们的新家伙不那么成功,而你迅速设计了一个新款:

 

注意,你在插头上多分了一段触头来处理麦克风信号,但麻烦的是,你的Qxyzrhjjjjukltk 2.1并不知道插进来的耳机是否有个麦克风,它需要知道这个信息才能决定是否启动电话功能。因此你发明了一个小协议……新设备在麦克风针脚上输出一个信号,在地线针脚上检测这个信号,如果有,它一定是3段式插头。否则说明没有麦克风,于是你会进入到兼容模式,只播放音乐。很简单,但这是一个协议磋商。

现在已经不再是一个一对多的市场了。所有的立体声设备由一个厂家制造,一个版本接着另一个版本,因此我要称之为系列对多的市场:

 

下面是一些你已经知道的系列对多的市场:

  1. Facebook | 约 20,000 个Facebook 应用
  2. Windows | 约 1,000,000 个Windows 应用
  3. Microsoft Word | 约 1,000,000,000 份Word文档

还有几百个其他的例子。要记住的是,当左手边的设备的新版本发布时,它必须保持自动向后兼容所有右手边的老的附件,因为那些老的附件在设计的时候可能不会考虑要连接新设备。火星人的耳机已经造出来了。你不可能回去把它们都改了。相比之下,改变新发明的设备以使其在连接旧耳机时表现得像个旧设备,
要容易得多,也更合常理。

因为你想要进步,增加新的特性和功能,你也需要一个新的协议让新的设备使用,合乎常理的做法是让两种设备在一开始时协商一下来确定它们是否都理解最新的协议。

微软是在系列对多的世界里成长起来的。

但还有一个多对多市场。

又过了好多年;你还在像疯子一样卖Qxyzrhjjjjukltk;但如今市场上有很多克隆的Qxyzrhjjjjukltk,比如开放源码的FireQx,还有很多耳机,你不断地发明需要改变耳机插头的新特性。这使得耳机制造商快发疯了,因为他们必须在每一种克隆Qxyzrhjjjjukltk上测试他们的新设计,这又耗时又费钱。并且老实说,他们中的大多数没有时间,只是在最流行的 MP3 5.0 上测过。如果测试通过,他们就很高兴。但是,当然了,当你把耳机插到 FireQx 3.0 时,它在你手里炸了,只是因为轻微地误解了规范里一段晦涩的、没人真正明白的内容,这段内容叫 hasLayout。人人都可以理解,当雨天时,hasLayout属性是true,电压会提高以支持挡风玻璃雨刷特性,但是对冰雹和下雪天是否也作为雨天来启用haslayout似乎存在一些争论,因为规范里没有说。FireQx 3.0 把雪天也当作雨天,因为下雪的时候你也需要雨刷,Qxyzrhjjjjukltk 5.0不这样,因为开发这个特性的开发员生活在火星上一个温暖的不下雪的地区,也没有驾照。是的,他们在火星上没有驾照。

最终一些讨厌鬼在他们的blog上写了一些长篇大作,详细解释了一个技巧,你能利用它来使Qxyzrhjjjjukltk 5.0表现得像FireQx 3.0一样。这个技巧利用了 MP3 5.0 里的一个高级bug来欺骗Qxyzrhjjjjukltk:通过融化一点点雪,让它在下雪的时候也以为是下雨。这很荒谬。但人人都在这么做,因为他们必须解决 hasLayout的不兼容。后来,Qxyzrhjjjjukltk团队在6.0中修正了这个bug,你再一次抓狂,你不得不去找某个可利用的新的bug来让装备了风挡雨刷特性的耳机可以适用于这两种设备。

现在。这就是多对多市场。左边有许多播放器各不相同,右边有数以亿计的耳机。两边都在犯错误,因为是人总会犯错。

 

不用说,这就是我们在面对HTML时的相同处境。几十种通用浏览器,亿万网页。

 

多年来,在多对多市场上发生的事情,就是呼吁“标准”,这样“所有的播放器”(特别是那些小播放器)都有同样的机会可以去正确显示所有8亿个网页,更重要的是,那8亿个网页的设计者们只需在一个浏览器上测试,只要遵照“web标准”,他们的网页在其它的浏览器上也能行,而无需在每个浏览器上测试每个网页。

 

看到了吧,想法就是,不是多对多的去测试,而是多对标准,标准对多的去测试,你的测试少了可不止一点点。更不要说,你的网页再也不需要任何针对特定浏览器的代码去解决不同浏览器的bug,因为在这个理想世界里,没有bug。

那就是理想。

实际上,web还有点小问题:没法去对照标准测试一个网页,因为没有任何参考实现(Reference Implementation)来保证,如果它没问题,所有的浏览器都没问题。就是不存在这样的参考实现。

所以面对一堆你没读过的,或者读了也不能完全理解的标准文档,你只能去用你的头脑去“测试”,纯粹作为一种思维实验罢了。

那些文档超级难懂。文档里充满了诸如这样的句子:“如果一个兄弟块框(它不漂浮且不是绝对定位的)跟着一个插入框,插入框将变成块框的第一个行内框。一个插入框不能插入另一个块,如果那个块已经以一个插入框开始或是它自己就是一个插入框。”每当我读到这样的句子,我纳闷,怎么有人能以正确的遵从规范。

没有可行的方法来检查你刚写好的网页是否符合规范。是有些校验器(Validator),但它们不会告诉你这个网页会被如何显示,一个把所有的文字叠在一起看不清的,但是却是“有效的”网页也没什么用处。人们所做的只是针对某个或某两个浏览器去检查,直到它看起来正常。假如他们犯了一个错,但是在IE和Firefox里看起来没问题,他们也不会知道自己犯了错。

当新出来一个浏览器/或版本时,他们的页面可能就看不了了。

如果你曾经访问过耶路撒冷最传统的犹太人社区,那里所有的人都完全同意并严格遵守犹太法里的每个字词标点,你会发现除了对哪些是干净的食物有一般的规定之外,你并不会看到一个来自某个传统社区的祭司会希望在另一个传统社区的某位祭司家里吃东西。而web设计者们正在发现Mea Shearim的犹太人几十年前就知道了的道理:不会仅仅因为你们都同意一本书就能保证兼容性,因为法律是如此复杂,难懂,绕圈,几乎不可能对它们有足够的理解以避开陷阱和地雷,你还是直接要水果盘吧,比较安全。

当然,标准是一个伟大的目标,不过在你变成一个标准迷之前,你必须要理解,由于人类的弱点,标准有时会被错误地解释,有时会令人困惑,甚至模棱两可。

这里真正的问题是,你在假设,有一个标准,但是由于没有人有一个方法去对照标准进行测试,这不是一个真正的标准:它是一种柏拉图式的理想和一系列的误解,因此标准并不能如人民希望的那样减少在多对多市场上的测试矩阵。

DOCTYPE是一个神话。

一个web设计者挂了一个DOCTYPE标签到他的网页上,说,“这是标准的HTML”,这是一种很傲慢的举止。但他们不会知道。他们要说的只不过是这个网页应该是一个标准的HTML而已。他们所真正知道的只不过是他们已经在IE、Firefox,也许还有Opera和Safari上测试过,看起来正常而已。或者是,他们从一本书上把DOCTYPE标签拷出来,却并不知道这意味着什么。

在真实世界里,人们不是完美的,你不可能只用一个规范就建立一个标准——你必须有一个超级严格的参考实现,每个人都只对照这个参考实现去测试。要不然,你会得到17份不同的“标准”,或者一份也没有。

这就是Jon Postel在1981年引起的问题所在,那年他造了一个新词,健壮性原则:“严于律己,宽以待人”。他说要让协议牢靠地工作的最佳方法是,人人都非常非常小心的遵守规范,但同时对别人,如果他没有严格遵守规范,要极度宽容,只要你能体会出他的意思就行。

所以,从技术上说,要显示一段小字段落的方法是<p><small>, 但是很多人写成<small><p>,这从技术上来说是不对的,至于为什么,大多数web开发者也都不理解,而web浏览器原谅了这种写法,把文字变小,因为这显然是他们想要的。

现在,到处是充满了这些错误的网页,因为所有的老浏览器开发者们开发出了超级开明,友好,通融的浏览器,它们爱你,不在乎你是否犯了错误。这样就出现了大量的错误。Postel的“健壮性”原则并非真正可行。这个问题多年来都没人注意到。2001年,Marshall Rose最后写道

跟直觉恰恰相反,Postel的健壮性原则(“严于律己,宽以待人”)常常导致部署出现问题。为什么?当一个新的实现最初发布时,它可能会碰到一些有实现的一个子集。如果那些实现遵从健壮性原则,那么新实现中的错误很可能不会被察觉。新的实现接着会碰到一些流传不是很广泛的部署。好些新的实现重复着这个过程。渐渐地,不是那么正确的实现跑进那些比最初的实现要少些宽容的实现里。读者该知道接下来会发生些什么。

Jon Postel 理应为他对互联网的发明所做的巨大贡献而骄傲,实在是没有理由为他那非著名的健壮性原则而责怪他。1981年还是史前时期。要是你能告诉Postel,会有9千万未受训的人(而不是工程师),去创建网站,他们会干很多乱七八糟的事情,而某种被误导的慈善,使得早期的浏览器开发者接受了这些错误,总会显示这些网页,他就会明白,这是个错误的原则。而实际上,web标准理想主义者是对的。创建web的正确的方法,本应该是有一个非常非常严格的标准,每一个浏览器都应该明确指出你所有的错误,web开发者如果不知道如何“严谨地提交”,就不要去写到处出现的网页,除非知道怎么做。

但话说回来,如果真是那样,web就不会像它现在这样起飞。也许,我们还会用着由AT&T运营的巨大Lotus Notes网络。

该怎样会怎样能怎样。谁会在意。都已经这样了。我们无法改变过去,只能去改变未来。见鬼,即使是未来,我们能改变的也没多少。

如果你是Internet Explorer 8.0团队里的一名实用主义者,你的脑皮层里应该深深地烙有Raymond Chen的这些话。他写过一些Windows XP是如何无奈地去模拟老Windows版本里的一些bug行为的文章:

站在消费者的角度来看这个问题。你买了些软件,有X,有Y,还有Z。后来,你升级到Windows XP。你的电脑现在时不时死机。而软件Z根本用不了。你会告诉你朋友:“别升级到XP!经常死机。与软件Z也不兼容。”你会去调试你的系统以确定是软件X导致了死机,而软件Z用不了是因为它用了未公开的window消息吗?当然不会。你会去把XP退货了(你的X,Y,Z软件是几个月前买的,已经过了30天退货期了,你唯一可以退的是XP)。

你也在思考了吧,嗯? 让我们为这段话更新一下版本吧:

站在消费者的角度来看这个问题。你买了些软件,有X,有Y,还有Z。后来,你升级到Windows XPVista。你的电脑现在时不时死机。而软件Z根本用不了。你会告诉你朋友:“别升级到XPVista!经常死机。与软件Z也不兼容。”你会去调试你的系统以确定是软件X导致了死机,而软件Z用不了是因为它用了不安全的window消息吗?当然不会。你会去把XPVista退货了(你的X,Y,Z软件是几个月前买的,已经过了30天退货期了,你唯一可以退的是XPVista)。

微软内部理想主义者对实用主义者的胜利,我2004年就报道过了,直接解释了为什么Vista收到一片恶评,并且销售惨淡

而这些话又是如何说到IE团队身上的呢?

站在消费者的角度来看这个问题。你每天访问100个网站。后来你升级到IE 8。一半的网页显示混乱,Google地图根本用不了。

 

你会告诉你朋友:“别升级到IE 8! 所有的网页都显示得乱七八糟,Google地图根本用不了。”你会去查看源代码以确定X网站使用了非标准的HTML,而Google地图用不了是因为它使用了老版本IE里提供却从未被标准委员会接受的非标准JavaScript对象吗?当然不会。你会把IE 8卸了(那些网站不是你控制的,有些网页的开发者现在已经不在人世了。你唯一可以做的事情就是退回到IE 7)。

所以,如果你是IE 8团队的一个开发者,你首先要做到的是在系列到多市场上屡试不爽的事情。你们会做一些协议层的协商,对那些没有明确告诉你它们期待新行为的站点,继续模拟以前的行为,这样所有的现有网站继续可以用。你只会在那些在网页上写了一个小标记,说:“嗨!我与IE 8神交!来吧,请给我你的所有新货!”的时候,才会看到新行为。

实际上,那曾经是IE团队宣布的第一个决定,时间是1月21日。浏览器会自动考虑到现有网页,人们不必去修改网站以使它们能像在旧版本的、bug多多的被web开发者痛恨的IE 7里的那样。

一个实用主义的工程师会下结论,说IE团队的最初决定是正确的。但年轻的理想主义者“标准”人们受不了了。

他们说,IE需要提供一个web标准体验,而不必要求写一个特殊的“嗨!我已经在IE 8下测试过了”标签。他们对特殊标签感到恶心。所有这些该死的网页不得不写37个丑陋的hack以使它能够在5到6个流行的浏览器里可用。受够了这些丑陋的hacks!8亿个现有的网页,下地狱吧!

IE 团队掷了硬币。他们的第二个决定,我必须认为这不是最后的决定,是去做理想主义者的事。对所有声明“标准兼容”的网页,都认为它们是为IE 8设计的,并已经测试过了。

在我用IE 8访问过的几乎所有网站,都会有某种形式的失效。用了大量JavaScript的网页一般来说都彻底死翘。大量的网页只是有显示上的问题:比如内容跑到别的地方了,弹出菜单的中间会有个滚动条压着。有些站点有些更微妙的问题:它们看起来还行,但你点着点着,一些关键的表单却提交不了了,
或直接跑到了一个空白页。

这些并不是有错误的网页,它们通常是遵照web标准精心构建的网站。但由于IE 6, IE 7并非真正符合规范,因此那些网站里有一些hacks,比如说“在Internet Explorer上……把这个东西向右移17像素以补偿IE的bug”。

而IE 8还是叫IE。但已经没有了IE 7的bug,他们遵照规范把那个曾经左偏17像素的东西移了。所以现在,那些曾经的补偿都没用了。

IE 8无法正常显示大多数网页,直到你放弃,单击那个“像IE7那样做”的按钮。
理想主义者不在乎这些,他们要的就是让你去改那些网页。

那些网页中的一部分已经没法改了。它们可能刻在了CD-ROM上。它们的作者现在已经不在人世了。大部分的网页都是那些现在不知所措的人创建的,为什么这些网页,4年前花钱雇一个设计师开发的网页,现在看不了了呢?

理想主义者欢欣鼓舞,他们去IE团队的blog上,有生以来第一次为微软说了好话。

我看着我的表。

滴答,滴答,滴答。

几秒钟内,你开始看到有人在论坛上这么发贴

我下载了IE 8,有些bug。我的一些网站,比如"HP",读起来非常困难,因为页面变得非常非常小……我的网速也时不时会慢一下,我去google地图,页面上到处都是重叠的东西,真难用!

嗯。你们这些沾沾自喜的理想主义者,嘲笑这只菜鸟。顾客不是傻子。她是你妻子。不要嘲笑了,98%的人会装IE 8,然后说“有bug,我看不了我的网页。”他们不会为了你们这些愚蠢的对开发一个合乎有点神话般的,柏拉图式的规范的浏览器有着宗教般狂热的人打响指。而这个标准并没有在任何一个地方被实现过。理想主义者不想听你们讲那些肮脏的hacks。他们只希望web浏览器只接受真正的网站。

看到了吧,这是个多么可怕的例子,说明了两个阵营之间的鸿沟。

web标准阵营看起来是左翼的。但你要真的开发了一个网页,声称符合标准,而事实上却不是,理想主义者就会变身为美国最严厉的州长Joe Arpaio:“你犯错了,活该你的网站看不了。我不在乎你的80%的网页都看不了了,我会把你们全都关进监狱。在那里你们会穿上粉红色的囚裤,吃15分钱的三明治,排队干活。而且我并不在乎把整个郡的人都扔进监狱。法律就是法律。”

另一方面,我们有实用主义者、敏感的、热心的、温柔的工程类型。“我们不能默认为IE 7模式吗?只用1行代码……打包!解决!”

是秘密吗?这就是我思考的会发生的事情。IE 8团队会告诉每个人IE 8默认会使web标准,在漫长的beta测试期内,他们会请求人们在IE 8里测试他们的网页,并让它们正确运行。当他们临近发布时,世界上只有32%的网页可以正确显示。
他们会说,“看,伙计们!我们真的很抱歉,我们真的想让IE 8默认使用web标准模式。但我们没法发布一个不能用的浏览器。”他们会回到实用主义者的决定上来。也许他们不会,因为实用主义者离开微软权力层已经有些时日了。如果是这样,IE 会失去很多市场份额。但理想主义者会雀跃,或许Dean Hachamovitch的年终巨奖也不会少一分钱。

看到了吗?没有正确答案。

通常,理想主义者在道理上是100%的正确;通常,实用主义者在现实里正确。口水仗会持续数年。这场争论把世界分成两半。如果你有办法可以买到互联网口水仗的股票,现在是一个不错的入市时机。





posted @ 2008-03-24 20:46 何睿 阅读(32) | 评论 (0)编辑

2007年12月21日

Tips
1.JIT编译器将本地CPU指令保存在动态内存中,一旦应用程序终止,编译器代码会被丢弃。所以,如果将来再次运行程序,编译器将再次将IL编译成本地指令。
2.protected internal,是指方法可以由任何程序集中的派生类,或者统一程序集中的任何类型访问。

posted @ 2007-12-21 22:10 何睿 阅读(58) | 评论 (0)编辑

2007年10月27日

int a = 9;
a += a++ + a++;
在.net 2005中,C++编译运算结果为a=29;c#运算结果为a=28;
为什么呢?C#的运算符执行顺序和C++不同??
大家说说

posted @ 2007-10-27 16:32 何睿 阅读(21) | 评论 (0)编辑

2007年9月17日

 

*         According to the SOAP standard, a fault can have an Action, a Code, and a Reason. The Action is controlled by the Action property. The Code property and Reason property are both properties of the System.ServiceModel.FaultException class, which is the parent class of the generic System.ServiceModel.FaultException

*         Catch Fault Exceptions in the Correct Order

    Because FaultException derives from FaultException, and FaultException derives from CommunicationException, it is important to catch these exceptions in the proper order. If, for example, you have a try/catch block in which you first catch CommunicationException, all specified and unspecified SOAP faults are handled there; any subsequent catch blocks to handle a custom FaultException exception are never invoked.

Remember that one operation can return any number of specified faults. Each fault is a unique type and must be handled separately

即先处理具体错误,再处理一般错误.

*             The Windows Communication Foundation (WCF) security has three common security modes that are found on most predefined bindings: transport, message, and "transport with message credential." There are two additional modes that are specific to two bindings: the "transport-credential only" mode found on the BasicHttpBinding, and the "Both" mode, found on the NetMsmqBinding.

*        When setting the security mode to TransportWithMessageCredential, the actual mechanism that provides the transport-level security is determined by the transport. For HTTP, the mechanism is SSL over HTTP (HTTPS); for TCP, it is SSL over TCP or Windows.

If the transport is HTTP (using the WSHttpBinding), the transport-level security is provided by SSL over HTTP. In that case, you must configure the computer hosting the service with an SSL certificate bound to a port, as shown in this topic.

If the transport is TCP (using the NetTcpBinding), by default the transport-level security is provided Windows security, or SSL over TCP. When using SSL over TCP, you must specify the certificate using the SetCertificate method, as shown in this topic.

The KnownTypeAttribute allows you to specify, in advance, the types that should be included for consideration during deserialization. For a working example, see the Known Types Sample example.

*              Normally, when passing parameters and return values between a client and a service, both endpoints share fully all of the data contracts of the data to be transmitted. However, there are circumstances in which this is not the case:

·   The sent data contract is "derived" from the expected data contract (for more information, see the section about inheritance in Data Contract Equivalence). In that case, the transmitted data does not have the same data contract as expected by the receiving endpoint.

·   The declared type for the information to be transmitted is an interface, as opposed to a class, structure, or enumeration. Therefore, it cannot be known, in advance, which type that implements the interface is actually sent and therefore the receiving endpoint cannot determine, in advance, the data contract for the transmitted data.

·   The declared type for the information to be transmitted is Object. Because every type inherits from Object, and it cannot be known in advance which type is actually sent, the receiving endpoint cannot determine in advance the data contract for the transmitted data. This is a special case of the first item: Every data contract derives from the default, a blank data contract that is generated for Object.

·   Some types, including .NET Framework types, have members that fall under one of the preceding three categories. For example, Hashtable uses Object to store the actual objects in the hash table. When serializing these types, the receiving end again cannot determine in advance the data contract for these members.

*        Round-tripping

Round-tripping occurs when data passes from a new version to an old version and back to the new version of a data contract. Round-tripping guarantees that no data is lost. Enabling round-tripping makes the type forward-compatible with any future changes supported by the data contract versioning model.

To enable round-tripping for a particular type, the type must implement the IExtensibleDataObject interface. The interface contains one property, ExtensionData (returning the ExtensionDataObject type). The property is used to store any data from future versions of the data contract that is unknown to the current version

posted @ 2007-09-17 17:54 何睿 阅读(88) | 评论 (0)编辑