The wind call my name

用知识和思考来丈量世界
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

《Programming .Net Components》学习笔记(二)

Posted on 2007-04-30 08:43  徐鸿翼  阅读(652)  评论(0编辑  收藏  举报

一、隐式转换和显式转换
直接把类实例委派给接口变量被称作“隐式转换”:

   IMyInterface obj; 
   obj
=new MyClass(); 
   obj.Method1(); 

当使用隐式转换时,编译器会强制类型安全,如果类MyClass没有实现接口IMyInterface,编译器会拒绝生成代码并产生一个编译时错误。编译器之所以这样执行是因为它可以读取类MyClass的元数据并预知该类是否继承于接口IMyInterface。但是,有一些转换不可以使用隐式转换。这种情况下可以使用显式转换。即从一种类型到另一种类型: 

    IMyInterface obj; 
    obj
=(IMyInterface)new MyClass(); 
    obj.Method1(); 

但是,切记对接口的显式转换是建立在牺牲类型安全之上的。即使类MyClass不支持接口IMyInterface,编译器仍会编译通过代码,.Net会在转换失败时抛出一个运行时异常。

二、为什么不使用隐式转换
 
一个使用隐式转换不能实现的例子是,应用非泛型类工厂(工厂方法模式,抽象工厂模式)。使用类工厂的模式的好处是仅类工厂与提供接口实现的组件类型耦合,客户端只需要知道接口。当需要变更服务提供者时,仅需要修改该工厂,而不影响客户端。当使用一个返回公共类型(通常是Object)的类工厂时,可以使用显式转换把对象转换为接口类型: 

    public interface IClassFactory 
    { 
         
object GetObject(); 
    }  
    IClassFactory factory; 
    
/* Some code to initialize the class factory */ 
    IMyInterface obj; 
    obj
=(IMyInterface)factory.GetObject(); 
    obj.Method1(); 

另一个隐式转换不适用的例子是当要使用一个接口的实现类,而这个类是该类同样支持的另一个接口的引用。即使客户端通过隐式转换得到第一个接口,它仍旧需要通过显式转换得到第二个:

    public interface IMyInterface 
    { 
         
void Method1(); 
         
void Method2(); 
    } 
    
public interface IMyOtherInterface 
    { 
         
void Method3(); 
    } 
    
public class MyClass:IMyInterface,IMyOtherInterface 
    { 
         
public void Method1() 
         {
         
public void Method2() 
         {
         
public void Method3() 
         {
    } 
    
//Client-Side code; 
    IMyInterface obj1; 
    IMyOtherInterface obj2; 
    obj1
=new MyClass(); 
    obj1.Method1(); 
    obj2
=(IMyOtherInterface)obj1; 
    obj2.Method3(); 

三、如何避免显式转换带来的类型安全问题 
在所有这些使用显式转换的例子中,必须融入错误处理,当万一出现一个不支持的接口转换时,使用try-catch机制来捕获异常。注意,有一个更加安全的防御式方法来进行显式转换——as操作符。如果是合法的并给变量赋值,as操作符将执行转换。如果不可行,则as操作赋给接口变量null值,而不是异常。

    SomeType obj1; 
    IMyInterface obj2; 
    
/* Some code to initialize obj1 */ 
    obj2 
= obj1 as IMyInterface; 
    
if (obj2 != null
    { 
          obj2.Method1(); 
    } 
    
else 
    { 
          
//Handle error in expected interface 
    } 

总之,应当总是在客户端进行防御式编程(例如as操作符)。不能断言一个类一定支持一个接口——这样可以同时兼顾强健的错误处理及接口和实现分离,无论服务端是否使用显式接口实现。养成在客户端通过接口调用服务和强制隔离的习惯。

 
根据原版英文翻译总结的,所以不足和错误之处请大家不吝指正,谢谢:)