`

参 数

    博客分类:
  • CLR
 
阅读更多

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

默认情况下,CLR假定所有方法都是传值的。对于值类型的实例来说,很好理解,就是传给方法这个实例的副本。对于引用类型来说,我说其实传的也是一个副本,只不过这是引用的副本,但由于这个副本也是指向这个引用类型的实例,所以我们在方法中对这个引用的副本所指向的实例的修改都是修改的是实例本身。如面代码就是修改引用的副本指向的对象:

               public yinyong yy=new yinyong(2,"2");    //yinyong是自定义类

               MakeYinYong(yy);    //这里面的变量yy是引用yy的副本,但它同样指向上面new出的yinyong的实例

               public void MakeYinYong(yinyong y)

               {

                   y.Age = 1;

                   y.Name = "1";

               }

              修改之后yy.Age就变为了1  yy.Name就变为了"1"

在C#中可以使用关键字ref或out来以传引用(传址)的方式向方法传递参数。      关于ref out见这里1 

这时就不是副本了,而是变量真正的地址,对于值类型可以理解为传递的是实例本身,对于引用类型可以理解为传递的是引用本身。如下代码就是修改引用指向的对象:

               public yinyong yy=new yinyong(2,"2");    //yinyong是自定义类

               MakeYinYong(ref yy)  //这里面的变量yy是引用yy本身

               public void MakeYinYong(ref yinyong y)

               {

                   y.Age = 1;

                   y.Name = "1";

               }

              修改之后yy.Age就变为了1  yy.Name就变为了"1"

所以对于引用类型而言,如果在方法里仅仅是修改引用所指向的对象,是不是用传引用的方式是没有什么区别的。  但如果需要交换两个引用类型的对象的话,就有区别了,如下:

public yinyong yy1=new yinyong(1,"1");                               public yinyong yy3=new yinyong(3,"3"); 

public yinyong yy2=new yinyong(2,"2");                               public yinyong yy4=new yinyong(4,"4"); 

public void Swap(ref yinyong y1, ref yinyong y2)            public void Swap(yinyong y3,yinyong yy4)

 {                                                                                         {                                                          

    yinyong temp = y1;                                                              yinyong temp = y3;

        y1 = y2;                                                                                y3 = y4;

        y2 = temp;                                                                            y4 = temp;

  }                                                                                         }

Swap(ref yy1,ref yy2);                                                                     Swap(yy3,yy4);

label1.text=yy1.Age+yy2.Age;                                              label2.text=yy3.Age+yy4.Age;

//将换成功                                                                             //交换失败

使用了ref的交换会交换成功就不说了,  没有使用ref的交换没有成功,是因为Swap(yy3,yy4);里的yy3与yy4只是真正的引用yy3与yy4的副本,所以交换的仅仅是副本yy3与yy4,但在使用时label2.text=yy3.Age+yy4.Age; 这里的yy3与yy4是真正的引用,它们并没有被交换。

另外,上面我们看到两个Swap方法除了参数有无ref外并无区别,其实CLR允许根据有无out ref进行重载,即可以根据是传值还是传址进行重载。

ref必须初始化参数,可以在方法里读取参数的值及修改参数     out不需要初始化参数,必须在方法里初始化参数但不能读取参数的值

还有就是对于以引用的方式传给方法的变量,它的类型必须与方法签名中声明的类型相同, 如把上面的改成

public void Swap(ref Object y1, ref Object y2)

 {                                                                                     

        Object temp = y1;                                                          

        y1 = y2;                                                                               

        y2 = temp;                                                                           

  }      

Swap(ref yy1,ref yy2)       是无法通过编译的,尽管Object是所有类型的父类,但在引用的方式下是不行的。

 

可选参数和命名实参(C#4.0的新特性)

C#4.0中设计一个方法的参数时,可为部分或全部参数分配默认值。然后,调用这些方法的代码可以选择不指定部分实参,接受其默认值。编译器是按从左向右的顺序依次赋实参,但有时我们会想如果我们使用可选参数的话势必会出现实参数与形参数不同的情形,这要怎么处理呢?   其实在C#4.0的方法参数中可选参数必须位于没有默认值的参数之后,所以我们不用担心我们设置的实参没有赋予给没有默认值的形参。 对于后面的可选参数,如果我们只是想其中的几个不使用其默认值,我们还可以在方法的调用处使用命名参数,这样我们就不用写出全部可选参数的实参了。如下代码:

方法: public void Print(int i,int j,string s1,string s2,int i1=1,string s3="3",DateTime dt=default(DateTime),Guid guid=new Guid())

调用方法:  Print(1,2,"3","4",s3:"我不想使用默认值了",dt:DateTime.Now)    *

可为方法、构造函数、有参属性(索引器)等的参数指定默认值。

如果参数用ref或out关键字进行了标识,就不能设置默认值。但调用时使用命名实参,如下:

方法:private void M(ref int i){ }

调用方法: int a=5;  M(i:ref a);

如以上*处所示,调用方法时,命名实参只能出现在实参列表的尾部。

还有一种可能性要注意,当被调用的方法位于另一个程序集里,当被调用的方法修改了某个参数的默认值,那么我们调用该方法的程序集需要重新编译。

 

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

可以在方法参数中使用params关键字。但注意的是params关键字只能应用于方法签名中的最后一个参数,而且这个参数只能是一个任何类型的一维数组。

我们可以来看加params和不加params的区别

public void  Params1(string s,params int[] ints)

    {

        int sum = 0;

        foreach (var item in ints)

        {

            sum += item;

        }

        Label1.Text = s + sum.ToString();

    }

    public void Params2(string s, int[] ints)

    {

        int sum = 0;

        foreach (var item in ints)

        {

            sum += item;

        }

        Label1.Text = s + sum.ToString();

    }

方法的声明除了params的区别以外没有任何区别,但调用的时候就不一样了

Params1("和是:", 1, 2, 3, 4, 5, 6, 7, 8, 9);

Params2("和是:",  new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9 });

可以看到第一种更方便一些,而实际上我们用第一种方式时C#编译器是将其代码编译成和第二种方式一样的IL代码。

对于第一种方式当没有参数要传递的时候可以传递null   Params1("没有传递参数", null);   这样C#编译器将不会构造一个数组。

public void Params(params Object[] objects) {...}  这样我们就可以传递任何数量任何类型的参数了

Params(new Object(),5,"Richard",new Random());

但由于C#编译器要构造数组,所以会有一些额外的性能损失。所以对于一些常用的方法我们还是不要只是定义包含params关键字的方法,而要重载一些不包含params关键字的方法,这样只有在很特殊的情况下才调用包含了params关键字的方法。

分享到:
评论

相关推荐

    单 反 相 机 的 十 大 参 数 设 置

    单 反 相 机 的 十 大 参 数 设 置

    命 令 行 参 数 处 理

    是大师的 的方式的 提供的后果的时光的法国

    风 机 盘 管 参 数 尺 寸.doc

    文档“风机盘管参数尺寸.doc”提供了不同型号的风机盘管的技术规格,这些风机盘管主要应用于建筑暖通空调系统中。风机盘管是中央空调末端设备,负责将处理过的空气送入室内,以调节室内温度和湿度。...

    西门子 840D SL 数控系统的数据备份

    驱 动 数 据 包 括 驱 动 器 数 据、 伺 服 参 数、 轴 参 数 等; 硬 盘 数 据 包 括 系 统 服 务 软 件、 操 作 系 统 软 件、 用 户 软 件、 及 数 据 管 理 等; CF 卡 数 据 包 括 SINUMERIK OPERATE ( 以 下...

    [asp dll 函数 web 组件 源码]鱼鱼asp函数组件(fishasp20090218.dll)

    '参 数:str ----字符串内容 '返回值:字符串长度 '**************************************************** '**************************************************** '函数名:CutStr(str, strlen) '作 用...

    二手房销售管理信息系统

    '参 数:无 '返回值:无 ' ****************************************************************************** Sub Main() '启动登陆窗体 Dim fLogin As New frmLogin fLogin.Show vbModal If Not ...

    人民政府教育机构大型网站

    参 数:num--------------调用条数 fontnum----------显示文字长度 d----------------显示类型,0不显示,1时间,2点击数,3作者 2、首页站点频道标题调用 标签:$show_titletext(num,fontnum,classid,classyes,...

    手写体数字字符识别算法仿真比较研究

    1 0  0 0 0 个 手 写 体 数 字 样 本 训 练 神 经 网 络 数 据 传 输 过 程 中 的 参 数, 用 縣 所 得 神 经  网 络 参 数 进 行 手 写 体 数 字 识 别 仿 真 测 试 。比 较 4种 算 法 的 仿 真 效 果 ...

    [php]mysql数据库操作——DB类

    -- 参 数:$host 数据库主机地址(必填) $user 数据库用户名(必填) $pass 数据库密码(必填) $data 数据库名(必填) $conn 数据库连接标识(必填) $code 数据库编码(必填) -- 返回值:无 -- 实 例:无 *******...

    UPS逆变器的重复控制器参数的仿真分析.mht

    介 绍 了 重 复 控 制 器 的 基 本 原 理 , 详 述 了 重 复 控 制 器 中 一 个 关 键 参 数 对 系 统 稳 态 误 差 和 收 敛 速 度 的 影 响 , 总 结 设 计 该 参 数 的 两 个 方 法 。 通 过 仿 真 分 析 , 解 释...

    led linux c源程序

    // 参 数: // pMenu 菜单指针 // bDirection 菜单的排列方向:DIRECTION_HORIZON 或 DIRECTION_VERTICAL // nRows,nCols 显示菜单的行数与列数,如果小于实际行数与列数将滚动显示 // nHDistance, ...

    java基础入门教程

    今 年 6月 7日 ,由 SUN公 司 和 台 湾 经 济 事 务 部 信 息 发 展 局, 台湾信 息 技 术 研究 所 等 单 位 牵 头 ,成 立 了 一 个 "Java联 盟 ", 参 加 的 有 22个 在 台 湾相 当 著 名 的 计 算 机公 司 ,并 在 台 ...

    各种共用代码集合

    // 参 数: [oldDate] - 要转换的日期 // [oldTime] - 要转换的时间 // 说明: 把日期转化为标准格式 方便数据库进行时间比较 2011-1-1 转换为 2011-01-01 // 把时间转化为标准格式 方便数据库进行时间比较 9:1:...

    不同超混沌系统的自适应修正函数投影

    研 究 了 具 有 未 知 参 数 的 LorenzStenflo( LS)系 统 和 一 种 新 型 超 混 沌 系 统 以 及 LS 系 统 和 超 混 沌 Chen 系 统 的 修 正 函 数 投 影 同 步 问 题 . 利 用 ...

    样条曲线的生成

    基于DXF文件格式的三次参数样条曲线的生成,三 次 样 条 曲 线 在 使 用 中 存 在 局 限 性 且 表 示 方 法 , 了折 方 面 消 除 了 三 次 参 数 样 条 曲 线 的 振 荡 和 回 章 虎 冬 [ 2 ] [ 7 ] 缺 乏 几 何 不 ...

    Mifare卡LockSDK V3.3酒管软件接口_160301

    参 数:keyA: 密钥, 六字节, 卡片的默认密钥是 "ffffffffffff" sector_no: 扇区号, 1~40 返回值:错误类型 描 述:验证卡片的相应扇区的密钥, 验证过后才可以读写 例 子:keyA = "ffffffffffff", sector_no = 3 ...

    mcgs脚本函数

    第二章数据对象操作函数 AnswerAlm DatName 函数意义:应答数据对象DatName 所产生的报警 如对应的数据对象没有报警产生或已经 应答 则本函数无效 返 回 值:数值型 0 为操作成功;...参 数:DatName 数 [更多]

    异步电动机直接转矩控制系统的设计与仿真研究

    机 的 参 数 , 对 参 数 的 变 化 很 敏 感 , 而 电 机 参 数 在 电 机 运 行 过 程 中 往 往 是 变 化 的 , 这 就 使 得 矢 量 变 换 控 制 技 术 的 实 际 控 制 效 果 难 以 达 到 理 论 分 析 的 结 果 , 至...

Global site tag (gtag.js) - Google Analytics