选择显示字体大小

漫谈c#编程中的多态与new关键字


  1. 你通常怎样用多态?

  假设我有一个类,里面有一个 printstatus 方法,用于打印实例的当前状态,我希望该类的派生类都带有一个 printstatus 方法,并且这些方法都用于打印其实例的当前状态。那么我会这样表达我的愿望:

// code #01

class base
{
 public virtual void printstatus()
 {
  console.writeline("public virtual void printstatus() in base");
 }
}

  于是我可以写一个这样的方法:

// code #02

public void displaystatusof(base[] bs)
{
 foreach (base b in bs)
 {
  b.printstatus();
 }
}

  bs 中可能包含着不同的 base 的派生类,但我们却可以忽略这些“个性”而使用一种统一的方式来处理某事。在 .net 2.0 中,xmlreader 的 create 有这样一个版本:

public static xmlreader create(stream input);

  你可以向 create 传递任何可用的“流”,例如来自文件的“流”(filestream)、来自内存的“流”(memorystream)或来自网络的“流”.networkstream)等。虽然每一中“流”的工作细节都不同,但我们却使用一种统一的方式来处理这些“流”。

  2. 假如有人不遵守承诺...

  displaystatusof 隐含着这样一个假设:bs 中如果存在派生类的实例,那么该派生类应该重写 printstatus,当然必须加上 override 关键字:

// code #03

class derived1 : base
{
 public override void printstatus()
 {
  console.writeline("public override void printstatus() in derived1");
 }
}

  你可以把这看作一种承诺、约定,直到有人沉不住气...

// code #04

class derived2 : base
{
 public new void printstatus()
 {
  console.writeline("public new void printstatus() in derived2");
 }
}

  假设我们有这样一个数组: // code #05

base[] bs = new base[]
{
 new base(),
 new derived1(),
 new derived2()
};

  把它传递给 displaystatusof,则输出是:

// output #01

// public virtual void printstatus() in base
// public override void printstatus() in derived1
// public virtual void printstatus() in base

  从输出结果中很容易看出 derived2 并没有按照我们期望的去做。但你无需惊讶,这是由于 derived2 的设计者没有“遵守约定”的缘故。

  3. new:封印咒术

  new 似乎给人一种这样的感觉,它的使用者喜欢打破别人的约定,然而,如果使用恰当,new 可以弥补基类设计者的“短见”。在 creating a data bound listview control 中,rockford lhotka 就示范了如何封印原来的 listview.columns,并使自行添加的返回 datacolumnheadercollection 的 columns 取而代之。

  从 output #01 中我们可以看到,new 只是把 base.printstatus 封印起来而不是消灭掉,你可以解除封印然后进行访问。对于 derived2 的使用者,解封的方法是把 derived2 的实例转换成 base 类型:

// code #06

base d2 = new derived2();
d2.printstatus();

// output #02

// public virtual void printstatus() in base
而在 derived2 内部,你可以透过 base 来访问:

// code #07

base.printstatus();

  这种方法是针对实例成员的,如果被封印的成员是静态成员的话,就要透过类名来访问了。

  4. 假如 base.printstatus 是某个接口的隐式实现...

  假如 base 实现了一个 iface 接口:

// code #08

interface iface
{
 void printstatus();
}

class base : iface
{
 public virtual void printstatus()
 {
  console.writeline("public virtual void printstatus() in base");
 }
}

  我们只需要让 derived2 重新实现 iface:

// code #09

class derived2 : base, iface
{
 public new void printstatus()
 {
  console.writeline("public new void printstatus() in derived2");
 }
}

  derived1 保持不变。则把:

// code #10

iface[] fs = new iface[]
{
 new base(),
 new derived1(),
 new derived2(),
}

  传递给:

// code #11

public void displaystatusof(iface[] fs)
{
 foreach (iface f in fs)
 {
  f.printstatus();
 }
}

  输出结果是:

// output #03

// public virtual void printstatus() in base
// public override void printstatus() in derived1
// public new void printstatus() in derived2

  从输出结果中,我们可以看到,虽然 derived2.printstatus 应用了 new,但却依然参与动态绑定,这是由于 new 只能割断 derived2.printstatus 和 base.printstatus 的联系,而不能割断它与 iface.printstatus 的联系。我在 derived2 的定义中重新指定实现 iface,这将使得编译器认为 derived2.printstatus 是 iface.printstatus 的隐式实现,于是,在动态绑定时 derived2.printstatus 就被包括进来了。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons