一、原来函数这样传参

   先看一个函数和函数调用。 

 static void Main(string[] args)
{
int num = ;
Test(num);//局部变量在使用之前赋值 //Test(10); //直接为局部变量赋值
}
static void Test(int i)//i 相当于一个局部变量
{
i++;
}

  Test函数定义了一个int 类型的变量i作为参数,这个地方相当于声明了一个局部变量,而局部变量使用之前必须赋值,这就是为什么函数使用的时候要赋值(传一个值进去)。

  假如不想给参数赋值怎么办?那就在函数声明参数的时候给参数(局部变量)赋值,这样调用函数的时候就可以不给参数传值。如下:

        static void Main(string[] args)
{
int x= Test();//可以不传值
int y= Test();//也可以传值
Console.WriteLine(x);
Console.WriteLine(y);
Console.Read(); }
static int Test(int i=)//为局部变量赋值,传参数的时候可以不为i赋值
{
i++;
return i;
}

  注意:赋初值的参数必须放在参数列表最右侧,可以有多个带初值的参数。

  作用:为参数赋了初值,在调用的时候可以赋值也可以不赋值,作用是为参数指定默认值,。

       static void  Test(int a,int b=, int i=)
{
//to do
}

 

  在为方法传参数的时候必须按照参数声明的顺序传,这个一直是这样做的,也没多想过,其实也可以不按照传参的顺序,如下:

        static void Main(string[] args)
{
Test2(s:"hello",b:true ,i:); //请看这个地方
Console.Read(); }
static void Test2(int i,string s,bool b)
{
Console.WriteLine(i);
Console.WriteLine(s);
Console.WriteLine(b);
}

  传参的时候指定哪个参数传什么值就可以不按照顺序传参,这个不是很常用,但是以前不知道,又长见识了。


补充:评论你有人问,如果有重载怎么办,这个问题,问得非常好。先看一下下面的代码

    static void Main(string[] args)
{
int x = Test();
int y = Test(,);
int z = Test(, , );
Console.WriteLine(x);//输出10
Console.WriteLine(y);//输出50
Console.WriteLine(z);//输出60
Console.Read(); }
static int Test(int i )
{
return i;
}
static int Test(int a,int b=)
{
return a + b;
}
static int Test(int a,int b=,int c=)
{
return a + b + c;
}

  当有重载的时候,不给带有默认值参数赋值,他会优先执行,不带默认参数的函数。


二、params 参数数组(可变参数)

    我们知道数组的长度是不可变的。当我们把一个数组作为参数传递的时候,想改变数组长度不是一件容易的事儿。params 参数数组就可以随便指定参数长度,也不用在传参的时候去特意定义一个数组传参。使用非常方便。

   例:

       static void Main(string[] args)
{
int[] arr = new int[]{,,,,};
Test1(arr);
Console.WriteLine();
Test2(,,,,,,);
Console.WriteLine();
Test2(,,);
Console.Read();
}
static void Test1(int [] arr )
{
for (int i = ; i < arr .Length ; i++)
{
Console.Write(arr [i]+" "); }
}
static void Test2(params int[] arr) //params 数组
{
for (int i = ; i < arr.Length; i++)
{
Console.Write(arr [i]+" ");
}
}

  params 参数数组,作为参数的时候,参数个数是可变的,当然也可以为0,但是用params 参数数组的时候,一个函数里只有一个params参数,并且必须放在参数列表的最后。

  params用法: 1、用来修饰方法的参数,而且只能修饰一维数组;

           2、一个方法只能出现一个params参数,并且必须把params参数数组放在最后,不能带有默认值;

           3、调用方法的时候,params修饰的参数,可以传一个数组,也可以传数组的元素,也可以什么都不传(长度就为0);

  在控制台应用程序中,如Console.WriteLine("我叫{0},今年{1}岁,喜欢{2}","Vivu","22","C#");其实就用到了params参数,这个重载就是:

  console.WriteLine(string.Format,Params string[] arr);         

  总结:params 参数修饰的数组相当于长度可变的参数数组。它是修饰参数(一维数组)的一个关键字。用处就是在不知道参数个数或参数个数有可能发生变化的情况下使用。

三、ref和out参数修饰符

ref: 

  值类型在传递值的时候,只是复制了一份值赋给另一个变量,另一个变量改变并不能改变原有的值。例如:  

            int num = ;
int a = num;
a -= ;
Console.WriteLine(num);//输出200
Console.WriteLine(a);//输出100

   但是,假如num代表我钱包里的钱,我把钱包交给别人(int a=num),别人用了100(a-=100),这时候,我钱包里的钱(num)应该是多少?按照上面的方式执行就会出错,钱包里的钱是不会变的,因为在传值的时候只是复制了num的一份值给a,a改变并不会改变num的值。那该怎么办???

   如果我传递的值是num的引用(可以理解为地址),那么a 改变了num就也会改变了。但是int 类型是值传递,怎么办,把它变为引用就要用到ref和out参数。

  ref和out参数的作用就是把值传递改为引用传递。

  改写上面的钱包的例子。

       static void Main(string[] args)
{
int num = ;
int res =Test(ref num );
Console.WriteLine(num );//输出100
Console.WriteLine(res );//输出100
Console.Read(); } static int Test(ref int a)
{
a -= ;
return a; }

  在内存图中分析一下ref参数:

  

  ref参数可以按引用类型传递,如果ref修饰的是引用类型的参数呢?先看下面的例子:

  先创建一个person类  

 private int _age;
private string _name; public string Name
{
get { return _name; }
set { _name = value; }
} public int Age
{
get { return _age; }
set { _age = value; }
}

Person类

  再看一下面ref修饰引用类型的情况。

     static void Main(string[] args)
{
Person p = new Person() { Name ="红红"};
Test1(p);
Console.WriteLine(p.Name); //输出什么???
TestRef1(ref p);
Console.WriteLine(p.Name); //输出什么???
Test2(p);
Console.WriteLine(p.Name); //输出什么???
TestRef2(ref p);
Console.WriteLine(p.Name); //输出什么???
Console.Read();
}
static void Test1(Person p)
{
p = new Person() { Name = "绿绿" };
}
static void TestRef1(ref Person p)
{
p = new Person() { Name ="蓝蓝"};
} static void Test2(Person p)
{
p.Name = "嘿嘿";
}
static void TestRef2(ref Person p)
{
p.Name = "掰掰";
}

  输出结果是,红红,蓝蓝,嘿嘿,掰掰。画一下内存图很好分析。引用类型本来传递的就是地址,所以引用类型使用ref参数和不使用是一样的。这里偷一下懒,想知道的去运行,画一下内存图吧!!!

  ref用法:1、使用ref必须在参数声明和调用的时候都带上ref关键字;

       2、只能修饰变量,不能修饰常量;

       3、ref在方法中可以对ref修饰的值不改变,但是在传参前必须给参数赋值;

out:

  ref 在使用之前必须赋初始值,它主要侧重于改变,修改值。使用ref,在函数声明与调用的时候必须在参数前面加上ref。out参数的作用与使用方法与ref类似,与ref不同的是out在使用前不必赋初始值,但在返回的时候必须为他赋值,所以out主要侧重于输出。out修饰符参数例子:

       static void Main(string[] args)
{
int num = ;
int b;
int a = TestOut(,out b);
Console.WriteLine(a);//输出100
Console.WriteLine(b);//输出200
Console.Read(); }
static int TestOut(int a,out int b)
{
b = a;
a -= ;
return a; }

总结:ref和out参数修饰符,都是把参数按引用类型传递,但是ref侧重于改变值,而out侧重于输出。一个函数只有一个输出值,但想返回多个值的时候就用out参数修饰符。

       ref在使用之前必须赋值,out在返回之前必须赋值。ref和out在函数使用和调用的时候,参数前面必须加ref和out参数。

【又长见识了】函数传参,params参数,ref和out参数详解的更多相关文章

  1. 【JS学习笔记】函数传参

    比如仅仅改变背景的颜色 函数传参:参数就是占位符. 那么在什么时候用传参呢?函数里定不下来的东西. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  2. c# 内存的具体表现- 通用类型系统 深拷贝 浅拷贝 函数传参

    c# 通用类型系统 及变量在 深拷贝 浅拷贝 函数传参 中的深层次的表现 在编程中遇到了一些想不到的异常,跟踪发现,自己对于c#变量在内存上的表现理解有偏差,系统的学习并通过代码实验梳理了各种情况下, ...

  3. 函数传参,改变Div任意属性的值&&图片列表:鼠标移入/移出改变图片透明度

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. x64汇编第三讲,64位调用约定与函数传参.

    目录 x64汇编第三讲,64位调用约定与函数传参. 一丶复习X86传参 二丶x64汇编 2.1汇编详解 x64汇编第三讲,64位调用约定与函数传参. 一丶复习X86传参 在x86下我们汇编的传参如下: ...

  5. python3 之 函数传参

    一.可变对象与不可变对象 在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象. 不可变类型:变量赋值 a=5 后 ...

  6. js函数传参

    函数传参:重用代码,首先保持html代码相对一致,把核心主程序用函数包起来,把每组不同的值找出来,通过传参的方式减少代码的使用 下面代码是我早期练习的,大家随便看看就好 <!DOCTYPE ht ...

  7. JS中的函数传参

    前言: 函数分为有参有返回值,有参无返回值,无参无返回值,无参有返回值:那么对于无参数的函数你想使用函数的调用怎么办呢?如果你想封装一个代码,实现多种功能,但是形参大于实参或者实参大于形参又该如何?本 ...

  8. 简单计算器的C实现-函数指针,main函数传参

    /** 程序功能:简单计算器,实现加减乘除平方* 作者版本日期:2015.11.08 zhouhb OK* 源代码:李明 <新概念C语言培训>第33集 C语言Shell命令解释器的实现* ...

  9. Python类三种方法,函数传参,类与实例变量(一)

    1 Python的函数传递: 首先所有的变量都可以理解为内存中一个对象的'引用' a = 1 def func(a): a = 2 func(a) print(a) # 1 a = 1 def fun ...

随机推荐

  1. 前端项目部署之Grunt

    如果你的前端项目很小或都者项目不需要通过专门的运维同学走流水线上线部署的话,那么可以略过以下的繁文. ok,Let's go! 我们看看如何使用grunt来部署上线项目? 前端项目一般分为两种类型:T ...

  2. 通过私有协议Chrome浏览器页面打开本地程序

    近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...

  3. String不变性

    String不变性理解类型: String x = "java"; System.out.println(x);//输出为java x.concat("java" ...

  4. CSS3+HTML5特效6 - 闪烁的文字

    先看效果 abcd 这个效果也比较简单,利用keyframes对文字的大小.透明度及颜色做循环显示. CSS <style> @-webkit-keyframes flash { 0%{ ...

  5. 动态创建一些常的html标签

    原文:动态创建一些常的html标签 一段时间来,不管是在学习还是应用asp.net mvc应用程序,较多情况之下,需要动态创建一些html标签.如这篇<文本框下面有两个铵钮,点就加点减就减> ...

  6. server正式的环境性能测试nginx-php 指着寻求突破的表现

    因为我是第三级城市语言.无法接触到更牛接触逼公司或环境.这是你母亲的现场环境摸过几次.截至完毕,测试已设法提高空间. 公司须要的站点执行环境.不能由于我这边的瓶颈而阻碍了公司进行,希望各位大能能不吝惜 ...

  7. 浅谈JavaScript性能

    最近在JavaScript性能方面有所感悟,把我的经验分给大家: 说到JavaScript,就不得不说它的代码的运行速度—— 在我初学JavaScript的时候,只是觉得它是一个很强大的脚本.渐渐的, ...

  8. Cocos2d-x 2.3.3版本 FlappyBird

    Cocos2d-x 2.3.3版本 FlappyBird   本篇博客基于Cocos2d-x 2.3.3, 介绍怎样开发一款之前非常火的一款游戏FlappyBird.本篇博客内容大纲例如以下:   1 ...

  9. UiAutomator源码分析之获取控件信息

    根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下 ...

  10. Robotium源码分析之运行原理

    从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...