zoukankan      html  css  js  c++  java
  • Chapter9 参数

    这章主要讨论了类型的成员——方法

    1.1 可选参数和命名参数

    private static void M(Int32 x=9,String s="A",DateTime dt=default(DateTime),Guid guid=new Guid())
    {
    Console.WriteLine("x={0},s={1},dt={2},guid={3}",x,s,dt,guid);
    }
    方法调用
    //1.等同于M(9,"A",default(DateTime),new Guid());
    //输出:x=9,s=A,dt=0001-01-01 0:00:00,guid=00000000-0000-0000-0000-000000000000
    M();
    
    //2.等同于M(8,"X",default(DateTime),new Guid());
    //输出:x=8,s=X,dt=0001-01-01 0:00:00,guid=00000000-0000-0000-0000-000000000000
    M(8, "X");
    
    //3.等同于M(5,"A",DateTime.Now,Guid.NewGuid());
    //输出:x=5,s=A,dt=2013-01-21 10:53:06,guid=871b8a7f-4991-4d26-8e51-10b74459b066
    M(5, guid: Guid.NewGuid(), dt: DateTime.Now);

    通过上面的代码基本可以看出给方法参数指定默认值及调用方法时的规则,下面列举方法指定了部分参数默认值时注意的规则和原则
    1.可以为方法、构造器方法和有参属性(C#索引器)的参数指定默认值,还可以为委托定义一部分参数指定默认值
    2.有默认值的参数必须放在没有默认值的所有参数之后。
    3.默认值必须是编译时能确定的常量值,C#认定的基元类型,枚举类型,可为Null的任何引用类型
    default 或new 关键字:
    这里对于任何一个值类型参数,可将默认值设为值类型的一个实例,上面设置两个结构(DateTime和Guid)的默认值时就采用的这两种语法
    如果是数值类型则=0
    如果是结构将返回初始化为0或null的每个结构成员
    如果是可为空的值类型,默认返回System.Nullable(Of T),它像任何结构一样初始化
    4.如果参数使用了ref或out关键字标记,就不能设置默认值。
    在调用时应该注意:
    1.实参可以按照任何顺序,但是,命名参数只能出现在实参列表的尾部。
    2.可以按名称将实参传给没有默认值的参数,但是要求所有所有实参都必须这样传递。
    3.C#不允许省略逗号之间的实参,比如M(1,,DateTime.Now)

    1.2 隐式类型的局部变量

    上面讨论了方法的可选参数和命名参数,下面在讨论方法中的局部变量
    C#的var
    例如:var name="jeff";
    由于"jeff"是个字符串,所以编译器能推断出name是String类型。
    var name=null;
    编译器报错:无法将<null赋予隐式类型的局部变量>,因为null能隐式转换为任何引用类型和可空值类型,无法确定其具体类型。
    总结:用var声明局部变量只是一种简化的语法,它要求编译器根据一个表达式推断具体的数据类型。var关键字只能用于声明方法内部的局部变量。
    容易混淆的:dynamic,它可用于局部变量、字段、和参数。

    1.3 以传递引用的方式向方法传递参数

    CLR在默认情况下方法参数都是传值的
    1.传递引用类型的对象时,会把该对象的一个引用(指向对象的一个指针)传给方法,这个引用(或指针)本身是以传值方式传给方法,这意味着方法能修改对象。调用者也能看到这些修改。
    2.对于值类型的实例,传给方法的是实例的一个副本,意味着方法修改的只是那个副本,调用者的实例不会受到影响。
    C#允许以传引用的方式传递参数
    关键字(ref或out)
    out标记的参数:不会使用调用方法之前初始化好的对象,被调用的方法不能读取参数的值。返回前必须向这个值写入。
    ref标记的参数:调用者必须在调用方法之前初始化参数的值,被调用的方法可以读取\写入值
    为值类型使用out和ref,效果等同于以传值的方式传递引用类型
    如果两个重载方法只有out和ref的区别,那么是不合法的,因为两个签名的元数据表示是完全相同的。

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

    关键字params,只能应用于方法签名的最后一个参数。这个参数只能标记任意类型的一个一维数组
    static Int32 Add(params Int32[] values){
    //other code
    }
    合法使用:
    Console.WriteLine(Add());//向Add传递new Int32[0]
    Console.WriteLine(Add(null));//向Add传递null:更高效(因为不会分配数组)
    一个方法获取任意类型、任意数量的参数
    static void DisplayTypes(params Object[] objs);
    注意:调用一个参数量可变的方法时,会造成一些性能的损失(传递null除外),毕竟,数组对象分配在堆上,元素数组必须初始化,最终也会被垃圾回收

    1.5 参数和返回类型的指导原则

    声明方法的参数类型时,应尽量指定最弱的类型,最好是接口而不是基类
    //好,该方法使用一个弱参数类型
    public void ManipulateItems<T>(IEnumerable<T> collection){....}
    //不好,该方法使用一个强参数类型
    public void ManipulateItems<T>(List<T> collection){....}

    因为调用第一个方法时,可传递数组对象、List<T>对象、String对象——实现了IEnumerable<T>接口的对象。
    如果方法需要的是一个列表(而非可枚举的对象),就应该将参数类型声明为Ilist<T> ,避免声明为List<T>
    这里只是讨论的集合,它是用一个接口体系结构来设计的。
    如果使用基类体系结构设计的,概念同样适用。
    //好,该方法是用一个弱参数类型
    public void ProcessBytes(Stream someStream){....}
    //不好,该方法使用一个强参数类型
    public void ProcessBytes(FileStream fileStream){....}

    相反,一般最好是将方法的返回类型声明为最强类型(以免受限于特定的类型)
    例如:
    //好:该方法使用一个强返回类型
    public FileStream OpenFile(){....}
    //不好:该方法使用一个弱返回类型
    public Stream OpenFile(){....}

    有时在不影响调用者的前提下修改方法的内部实现。OpenFile方法不可能更改内部实现来返回除FileStream之外的其他对象。
    但是如果某个方法返回一个List<String>对象,可能在未来的某个时候修改它的内部实现,以返回一个String[]
    //较灵活
    public IList<String> GetStringCollection(){.....}
    //较不灵活
    public List<String> GetStringCollection(){.....}
    1.6 常量性

  • 相关阅读:
    UVa LA 2965
    UVa LA 3695
    UVa LA 3029 City Game 状态拆分,最大子矩阵O(n2) 难度:2
    Uva LA 3177
    Uva LA 3902
    Uva 11520
    UVa Live 3635
    python学习笔记-day05 字典
    python学习笔记-day04 元组
    python学习笔记 day04 列表增删改查
  • 原文地址:https://www.cnblogs.com/hailiang2013/p/2869732.html
Copyright © 2011-2022 走看看