首先应该认清楚在C#中只有两种类型:

1、引用类型(任何称为“类”的类型)

2、值类型(结构或枚举)

先来认识一下引用类型和值类型的区别:

函数传参之引用类型:

1、先来一个简单的引用类型传参的实例:

//使用了C#6.0的一个新特性:using static System.Console;
class Program
{
static void StartTest1(string test)
{
test = "test2";
WriteLine(test);//输出:"test2"
} static void StartTest2(string test)
{
test = null;
WriteLine(test);//输出:(空白)
} static void Main(string[] args)
{
string test = "test1";
WriteLine(test);//输出:"test1" StartTest1(test);
WriteLine(test);//输出:"test1" StartTest2(test);
WriteLine(test);//输出:"test1"
}
}

输出结果:

test1
test2
test1 test1

结果分析:

首先明白字符串(string)类型是引用类型,但改变了它的值之后,并没有影响到函数外面那个实参的值,这可能与大家的常识有点相违背,因为我们都知道若是变量以"引用传递"的方式传递,那么调用的方法可以通过更改其参数值,来改变调用者的变量值,但这里有一点需要说明的是:"引用传递"不是等价于引用类型传参,这是很多人的误解的地方。其实在C#当中,引用类型和值类型默认都是以“传值”的方式传递数值(引用)的(引用类型的值就是引用(类似索引或地址),而不是对象本身)。
请看下图详细分析:

2、再来一个略微复杂的引用类型传参的实例:

 	class Program
{
static void StartTest1(StringBuilder test)
{
test.Append("test2");
WriteLine(test);//输出:"test1test2"
} static void StartTest2(StringBuilder test)
{
test = null;
WriteLine(test);//输出:(空白)
} static void Main(string[] args)
{
StringBuilder test = new StringBuilder();
test.Append("test1");
WriteLine(test);//输出:"test1" StartTest1(test);
WriteLine(test);//输出:"test1test2" StartTest2(test);
WriteLine(test);//输出:"test1test2"
ReadKey();
}
}

输出结果:

test1
test1test2
test1test2 test1test2

结果分析:

StringBuilder和string同样是引用类型,那为什么最终的StringBuilder类型值改变了呢?其实这里要纠正一下,真正改变的不是StringBuilder类型值(也就是引用的值),而是引用指向的字符数组引用指向的对象值改变了。在StringBuilder类里面封装了一个字符数组(最终的输出的就是这个字符数组,而那些操作也是对这个字符数组进行操作)。

结合上面两个实例,对于引用类型传参,从这里可以得出一个小结论:

1、在函数里面,若直接改变的是引用的值(也就是地址),那么之后的操作都不会影响到函数外面的那个变量
2、在函数里面,若直接改变的是引用指向的对象(值类型)的值(甚至更深层次的对象的值),那么就会影响到函数外面的变量

所以区分清楚改变的是引用的值还是引用指向的对象(值类型)的值是关键。

3、再来一个综合的引用类型传参的实例:

    class Program
{
class Test
{
public int index;//值类型
public StringBuilder builder;//引用类型
public string Result{
get{return $"{index}:{builder.ToString()}";}
}
}
static void StartTest(Test test)
{
test.index++;
test.builder.Append("test2");
WriteLine(test.Result);//输出:"2:test1test2" test.index = new int();
test.builder = new StringBuilder();
test.builder.Append("test3");
WriteLine(test.Result);//输出:"0:test3"
}
static void Main(string[] args)
{
Test test = new Test {
index = 0,
builder = new StringBuilder()
};
test.index++;
test.builder.Append("test1");
WriteLine(test.Result);//输出:"1:test1" StartTest(test);
WriteLine(test.Result);//输出:"0:test3"
}
}

输出结果:

1:test1
2:test1test2
0:test3
0:test3

结果分析:



[若是能够明白1和2中的分析,这个应该没有问题的]

函数传参之值类型:

简单的值类型传参这里就不演示了,来一个含有引用类型的值类型传参实例(只是将上例中的struct改为了class,这样好做对比):

    class Program
{
struct Test
{
public int index;//值类型
public StringBuilder builder;//引用类型
public string Result{
get{return $"{index}:{builder.ToString()}";}
}
}
static void StartTest(Test test)
{
test.index++;
test.builder.Append("test2");
WriteLine(test.Result);//输出:"2:test1test2" test.index = new int();
test.builder = new StringBuilder();
test.builder.Append("test3");
WriteLine(test.Result);//输出:"0:test3"
}
static void Main(string[] args)
{
Test test = new Test {
index = 0,
builder = new StringBuilder()
};
test.index++;
test.builder.Append("test1");
WriteLine(test.Result);//输出:"1:test1" StartTest(test);
WriteLine(test.Result);//输出:"1:test1test2"
}
}

输出结果:

1:test1
2:test1test2
0:test3
1:test1test2

结果分析:

首先应该明白,值类型以"传值"方式传递时,是一种浅拷贝,所以对于引用类型,只是复制了引用的值,副本(形参)中的引用指向的对象还是同一个。其他的自己分析应该明白。

结论:

1、无论是引用类型还是值类型,永远不会传递对象本身。涉及到一个引用类型时,要么以“引用传递”的方式(使用了ref或out关键字)传递变量,要么以“传值”的方式传递参数值(引用)。所以,通常函数传参(不论是引用类型还是值类型),都是以“传值”的方式传递的,只是要明白引用类型的值是引用本身(相当于一个索引或地址,而这个索引或地址最终指向的才是对象本身)。

2、“引用方式”传递与“传值”传递方式最大的区别就是“引用方式”要使用ref或out关键字修饰,所以以这个为标准去区分函数传参的方式(而不是以类型是引用类型还是值类型)。

3、对于传入函数的引用类型变量,最终会不会受到函数内部修改的影响,需要区分清楚函数内部改变的是引用的值还是引用指向的对象(值类型)的值。

C#篇(三)——函数传参之引用类型和值类型的更多相关文章

  1. 悉数 Python 函数传参的语法糖

    TIOBE排行榜是程序开发语言的流行使用程度的有效指标,对世界范围内开发语言的走势具有重要参考意义.随着数据挖掘.机器学习和人工智能相关概念的风行,Python一举收获2018年年度语言,这也是Pyt ...

  2. [Java]_函数传参的疑惑与思考

    问题来源于leetcode上的两道题 Path Sum I && II,分别写了两个dfs. void dfs(TreeNode node , int sum , ArrayList& ...

  3. python中给函数传参是传值还是传引用

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...

  4. python函数传参是传值还是传引用?

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...

  5. pytest十一:函数传参和 firture 传参数 request

    为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数.比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其它用例全部的调用这个登录函数就行.但是登录 ...

  6. 『Python × C++』函数传参机制学习以及对比

    一.Python函数传参 在python中,函数传参实际上传入的是变量的别名,由于python内在的变量机制(名称和变量值相互独立),只要传入的变量不可变(tuple中的元素也要是不可变的才行),那么 ...

  7. 函数传参传的是啥的思考【java Python】

    今天看<java 核心 卷1>的时候,作者提到了函数传参的问题,他提到,java传参,传的是值,而不是引用,然后,函数将要传的实参的值(如果实参是基本数据类型,那么就是值.如果实参是对象, ...

  8. JS——变量和函数的预解析、匿名函数、函数传参、return

    JS解析过程分为两个阶段:编译阶段.执行阶段.在编译阶段会将函数function的声明和定义都提前,而将变量var的声明提前,并将var定义的变量赋值为undefined. 匿名函数: window. ...

  9. pytest_函数传参和firture传参数request

    前言为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数. 比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其它用例全部的调用这个登陆函数就行. ...

随机推荐

  1. Android与server通信的方法之中的一个(json)效率不高安全性不好

    http通信.以xml或者json为载体.相互通信数据. Android对于http的网络通信,提供了标准的java接口--httpURLConnection接口.以及apache的接口--httpc ...

  2. 安装MYSQL错误“conflicts with file from package mysql-libs-*” 解决方法

    安装MYSQL的时候时: 错误现象: [root@localhost opt]# rpm -ivh MySQL-server-5.5.32-1.el6.x86_64.rpm Preparing... ...

  3. 图论之tarjan缩点

    缩点,就是把一张有向有环图中的环缩成一个个点,形成一个有向无环图. 首先我介绍一下为什么这题要缩点(有人肯定觉得这是放屁,这不就是缩点的模板题吗?但我们不能这么想,考试的时候不会有人告诉你打什么板上去 ...

  4. oracle 11g not in 与not exists 那个高效?

    网络上很多谣言是后面跟小表用not in,后面跟大表用not exists,难道真的是这样子的嘛? 情况下面测试: 1.先用小表测试(1000条记录和一张8万条记录的表): SQL> creat ...

  5. POJ 2132 暴搜OR Floyd

    题意: 给你一个邻接矩阵(n<=25)问所有1到2路径的gcd的lcm是多少. 一些经验(WA/TLE的经验): 1. 无脑暴搜 是会TLE的--. 2. 关于精度 dyf神牛说了:long l ...

  6. Java数据库连接——PreparedStatement的使用

    首先了解Statement和PreparedStatement的区别: 由此可见,一般使用PreparedStatement. 操作数据库SU(Course表),其中Course属性有Cno,Cnam ...

  7. python 时间差计算

    import time import datetime datebg=input("date begin:") dateed=input("date end:" ...

  8. Sublimi Text3 下Emmet使用技巧

    Emmet真的好用,可以少写很多代码. 初始化文档 HTML文档需要包含一些固定的标签,比如<html>.<head>.<body>等,现在你只需要1秒钟就可以输入 ...

  9. ZBrush中Z球(ZSphere和ZSphereⅡ)

    ZSphere可以让用户使用干净的拓扑结构快速建立一个基础网格,然后将其塑造成任何形状.ZSphere的强大在于它非常简单,用户可以从一个单一的ZSphere开始,然后轻松地在其上面增加新的ZSphe ...

  10. JavaScript 中表达式和语句的区别

    1.语句和表达式 JavaScript中的表达式和语句是有区别的.一个表达式会产生一个值,它可以放在任何需要一个值的地方,比如,作为一个函数调用的参数.下面的每行代码都是一个表达式: myvar3 + ...