C#系列文章之参数

解决的主要问题:

  1. 如何可选地制定参数
  2. 按名称指定参数
  3. 按引用传递参数
  4. 如何定义方法来接受可变数量的参数

文章的主要内容:

  • 可选参数和命名参数
  • 隐式类型的局部变量
  • 以传引用的方式向方法传递参数
  • 向方法传递可变数量的参数
  • 参数和返回类型的设计规范
  • 常量性

1.1可选参数和命名参数

在方法中为部分参数指定默认值的规则和原则:

  • 可为方法,构造器方法和有参属性(C#索引器)的参数,委托定义一部分的参数指定默认值。并且默认值必须是编译时能确定的常量值,可以是基元类型,枚举类型以技能设为null的任何引用类型。可以使用default和new来设置默认值
  • 不要重命名参数变量(否则调用者在以传参数名的方式传递实参时要修改代码)。如果方法被模块的外部进行调用,不要随意更改默认值,比如下面的例子:                            
    //不要这样做
    private static string MakePath(string filename="Untitled")
    {
        return string.Format(@"C:{0}.txt",filename);
    }
    //而要这样做
    private static string MakePath(string filename=null)
    {
        return string.Format(@"C:{0}.txt",filename??"Untitled");
    }
  • 如果参数用ref或out关键字进行标识,则不能设置默认值,因为没有办法为这些参数传递有意义的默认值。

调用方法时,传参数时规则和原则:

  • 命名参数只能出现在实参列表的尾部
  • 所有必须的实参必须都传递
  • 如果参数要求ref/out,为了以传递参数名的方式传递实参,要使用下面语法:
//方法的声明
private static void M(ref int x){.......}

//方法的调用
int a = 5;
M(x:ref a);

 此外不能用var声明方法的参数类型,不要混淆dynamic和var。用var声明局部变量只是一种简化的语法,他要求编译器根据表达式推断出具体数据类型,其只能声明方法内部的局部变量,而dynamic关键字适用于局部变量,字段和参数。另外,必须显示初始化用var声明的变量。

1.2以传引用的方式向方法传递参数(out ref)

     CLR默认所有方法参数都传值,对于引用类型,对象的指针被传给方法,这个指针也是当做值来传递的,意味着方法能修改对象。对于值类型,由于是在栈上,传给方法是一个副本,调用者中的实例不受影响。

     CLR不区分out和ref,无论用哪个都会生成相同的IL代码。元数据除了有一个bit用于说明是out还是ref外,剩下几乎一致。用out标记表明调用者在调用方法之前不指望你已初始化好了对象,被调用的方法不能读取参数的值,要求返回前必须向这个值写入。用ref标记,调用者就必须先初始化参数的值。为较大的值类型使用out,可提升代码执行效率,因为它避免了在进行方法调用时复制值类型实例的字段。

     CLR允许根据使用的是out 还是ref参数对方法进行重载,例如:

     

//如下两个方法可以实现重载,
//但是如果只有out和ref区别,则不合法,
//因为两个签名的元数据形式相同
public class Point
{
    void Add(Point p){.....};
    void Add(ref Point p){.....};
}

1.3 向方法传递可变数量的参数

   使用如下声明,接受可变数量的参数

  

int Add(params int[] values)
{
   int sum =0;
   if(values!=null)
   {
      for(int x = 0; x<values.length;x++){.....}
    }
   return sum
}

调用时可以是Add(new int[]{1,2,3...});也可以是Add(1,2,3...);

        编译器在检测到方法调用时,会检查所有具有指定名称同时参数没有应用ParamArray特性的方法。找到就生成调用它所需的代码,否则就检查应用ParamArray特性的方法,此时编译器生成代码构造一个数组,填充元素,再生成代码来调用所选的方法。

        只有方法最后一个参数才可以用Params关键字标记,也只能标识一组数组(任意类型),可传递null或不传值;

        调用参数数量可变的方法对性能有所影响(除非显式传递null)。毕竟数组对象必须在堆上分配,数组元素必须初始化,而且数组内存最终需要垃圾回收。为此可以定义几个没有使用params关键字的重载版本。

1.4 参数和返回类型的设计规范

        声明方法参数类型应尽量指定最弱类型,宁愿要接口也不要基类。比如处理一组数据项,最好用IEnumerable<T>,而不要用强数据类型List<T>或强接口类型ICollection<T>或IList<T>。原因是要尽可能使接受的参数范围广,更灵活。相反一般将方法返回类型声明为最强类型(防止受限于特定类型)。总之确保调用者调用方法有尽量大的灵活性,使方法适用范围更大。

         有时在不影响调用者前提下修改方法内部实现。如果方法返回List<string>,可能会在未来某个时候修改内部方法实现返回string[]。若想保持一定的灵活性,可以选择较弱的返回类型。比如IList<string>不建议使用最弱的IEnumerable<string>,也不使用较强的IConllction<string>

原文地址:https://www.cnblogs.com/mjys-gh/p/6459477.html