C#4.0新特性之(二)命名参数,可选参数与COM互操作

 C#4.0新特性之(二)命名参数,可选参数与COM互操作

1.简介

  之前C#(2.0)和java一样是一门的纯粹的面向对象的语言,他们都使用重载而不是可选参数。但是实际上使用的其他外部程序,COM组件却经常不要求指定所有参数(这在很多VC,VB编写的组件或者操作IronPython的对象的时候很常见,他们一直使用可选参数)。这会导致一个C#程序员不得不用Type.Missing塞满整个参数列表。不过C#4.0终于支持命名参数/可选参数了。程序员可以在方法调用的时候通过命名参数指定可选参数。而这一切都是为了让.Net 4.0的动态语言运行库(DLR)在动态绑定的时候具有更好的兼容性。

2.命名与可选参数

  这个对C#来说是又一个新特征,但对C++,VB,Python etc. 的程序员来说这只是很自然的一个特征。C# 4.0种的可选参数和其他语言中的用法大致相同,这里不需要VB中额外的关键词修饰,也不能像C++中只用点点点来表示可以无视,倒是和python比较像,下面的声明是合法的:

可选参数Foo
         static   void  Foo( int  a, String s  =   " i'm a string " , dynamic b  = null , MyClass c  =   null )

简单来讲,C#4.0中使用可选参数必须遵循以下几条原则:

0).可选参数必须有个编译时常量作为其默认值。如果是除String之外的引用类型(包括那个特殊的dynamic类型),默认值只能是null。下面的声明是不能通过编译的:

代码
         static   void  Foo( int  a, String s  =   " i'm a string " dynamic b  = 2, MyClass c = new  MyClass())

1).可选参数必须从右往左出现在参数列表中(必须后出现),可选参数右边的参数(如果有的话)必须是可选参数。下面的声明是不能通过编译的:

代码
         static   void  Foo(String s  = "i'm a string" ,  int  a, dynamic b  =   null , MyClass c  =   null )

 2).可选参数的赋值必须通过命名参数的方式指定,即必须使用可选参数的参数名称对其进行赋值。而非可选参数则不一定要用命名参数。如下的调用都是合法的:

Foo calls
            Foo( 2 );
            Foo(a: 
2 );
            Foo(
2 , s:  " hello " , b:  3.14 );
            Foo(
2 , s:  " hello " , b:  3.14 , c: new  MyClass());
            Foo(
2 , c:  new  MyClass());

 特别的,一旦调用方法时使用的是命名参数,则命名参数的位置可以是任意顺序,如下的调用是合法的: 

代码
            Foo(b: 3.14 , c: new  MyClass(), a: 2 );

唯一的影响就是上述调用中会对b先求值,然后再是c和a。函数总是按照参数出现的顺序进行求值操作的。 

  另外,可选参数不仅适用于普通的方法,还适用于构造器,索引器中,本质上它们没有什么不同。

3.可选参数与重载决策

  毫无疑问,命名参数和可选参数让CLR在方法的重载决策(overload resolution)变得稍微复杂了一些,不用担心,这里你只需要搞清楚重载决策的下面几个特点就可以了:

0).在带可选参数的方法签名中,重载决策会认可被可选参数代替的重载版本,比如下面两个声明:

        public   static   void  Foo( int  a, String s  =   " i'm a string " , dynamic b  =   null , MyClass c  =   null );
       
public   static   void  Foo( int  a, String s  =   " i'm a string " );

  如果按照以下方式调用,编译器会提示你它已经被上面两个方法confused了:

            Foo( 2 );
            Foo(a: 
2 );

1).在调用方式同样合法的情况下,重载决策会优先选择不带可选参数的重载版本。比如下面两个方法:

        public   static   void  Foo( int  a, String s  =   " i'm a string " , dynamic b  =   null , MyClass c  =   null );
       
public   static   void  Foo( int  a); 

  如果使用以下方式调用:被调用的会是void Foo(int a);这个版本:

            Foo( 2 );
            Foo(a: 
2 );

2).在调用方式同样合法的情况下,重载决策会优先选择类型最为匹配(最易转化)的重载,例如下面两个方法:

        public   static   void  Foo( byte  a, String s  =   " i'm a string " , dynamic b  =   null , MyClass c  =   null );
       
public   static   void  Foo( object  a);

   Foo(2)和Foo(a:2)都将调用前一个方法,因为int到byte是值类型之间的转化,其代价要比从int转到object的代价低。

4.C#4.0中的COM互操作

     在上一篇文章中提到的动态类型绑定和本文前面提到的命名参数,可选参数都为CLR的COM互操作提供了便利。有了动态类型,访问COM对象时不必再对返回的COM对象进行显式的类型转换了,因为返回的是一个dynamic类型的对象,我们可以直接在它上面调用方法/属性/索引器等,例如excelApp.Cells[row,column].Value = "some value"; 这里的Cells[row,column]返回的是一个dynamic类型的对象,而之前都是返回的object需要显式转换才能操作它,比如:((Excel.Range)excelApp.Cells[row,column]).Value = "some value";

     而有了可选参数,广大程序员们也不必再猛力用Type.Missing填充整个参数列表了,比如Office12的Excel.ApplicatioinClass中就利用了可选参数定义了一个intersect方法:

代码
public   virtual  Range Intersect(Range Arg1, Range Arg2,  object  Arg3  =  Type.Missing,  object  Arg4  =  Type.Missing,  object  Arg5  =  Type.Missing,  object  Arg6  =  Type.Missing,  object  Arg7  =  Type.Missing,  object  Arg8  =  Type.Missing,  object  Arg9  =  Type.Missing,  object  Arg10  =  Type.Missing,  object  Arg11  =  Type.Missing,  object  Arg12  =  Type.Missing,  object  Arg13  =  Type.Missing,  object  Arg14  =  Type.Missing,  object  Arg15  =  Type.Missing,  object  Arg16  =  Type.Missing,  object  Arg17  =  Type.Missing,  object  Arg18  =  Type.Missing,  object  Arg19  =  Type.Missing,  object  Arg20  =  Type.Missing,  object  Arg21  =  Type.Missing,  object  Arg22  =  Type.Missing,  object  Arg23  =  Type.Missing,  object  Arg24  =  Type.Missing,  object  Arg25  =  Type.Missing,  object  Arg26  =  Type.Missing,  object  Arg27  =  Type.Missing,  object  Arg28  =  Type.Missing,  object  Arg29  =  Type.Missing,  object  Arg30  =  Type.Missing);

 换做以前要手动指定这三十个参数的确是一件抓狂的事情。

      在性能方面,由于C#4种编译器可以把PIAs按需部分编译到你的程序集中,不必每次都完全load这组庞大的互操作程序集,这对提高COM交互性能很有帮助。另外还有一个语法糖就是在COM调用的时候可以不使用ref传递参数,这避免了程序员自行创建临时变量来hold这些参数,不过这里不使用ref并不代表不按引用传递而按值传递,实际上C#编译器会自行帮你创建临时变量并任然按引用把参数传递给调用者。

5.总结

     C#4.0中很大一部分特征弥补了它之前的一些令开发者不爽的地方,无论是动态类型还是可选参数,新的C#让那些和各种组件(COM,IronPython etc.)打交道的程序员获得一定程度的解脱。C#越来越变得以人为本,更确切地,以程序员为本。

 

Author: Freesc Huang @ CNBlogs 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值