C# List 作为参数传递的值变化

简介: 一、示例演示 namespace TestConsole { class Program { static void Main(string[] args) { Console.

一、示例演示

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("");

            List<string> list1 = new List<string>();
            Test1(list1);
            Console.WriteLine(" list1:" + list1.Count()); // 总数量为 1

            Console.WriteLine("");
            Console.WriteLine("---- 亮瞎眼的分割线 ----"); 
            Console.WriteLine(""); 

            List<string> list2 = new List<string>();
            Test2(list2);
            Console.WriteLine(" list2:" + list2.Count()); // 总数量仍为 0

            Console.WriteLine("");
        }

        static void Test1(List<string> list)
        {
            list.Add("1");
            Console.WriteLine(" Test1():" + list.Count()); // 总数量为 1
        }

        static void Test2(List<string> list)
        {
            List<string> list2 = new List<string>();
            list2.Add("1");

            list = list2;
            Console.WriteLine(" Test2():" + list.Count()); // 总数量为 1
        }
    }

可以发现:

经过 Test1后,list 的元素数量由 0 变为 1 了,

经过 Test2后,list 的元素数量还是0。

二、解说

1.list类型是引用类型

2.引用本身是类似于一个“保存地址的值变量”
所以从方法外部传入引用到方法里,那么其实引用本身是复制了一份副本来给方法里使用的,只是说这个复制的引用副本和之前的引用的内容(也就是所指向的对象内存地址)是一样的,所以通过引用操作对象的数据时,可以看到2个引用都操作的同一个对象;但如果你是修改了引用副本本身的值内容(将该引用指向了一个新的对象的内存地址),那么是不会影响到之前方法外的那个引用的,所以修改后会发现2个引用所指向的对象不同了

而如果对象引用参数前加上了ref,那么方法参数所传递的不再是引用的副本,而是引用的地址了(即通过引用的地址找到引用,再读出引用里保存的内存地址值,再根据则个地址值去找到真正要操作的对象),所以如果此时你再修改这个引用的值时,会根据引用的地址找到方法外的那个引用,然后修改其内容,所以会发现方法外的引用也会指向新的对象了

3这里有三段代码

你可以看看,体会一下:

(1)

List<string> list=new List<string>();
ModifyList(list);
Console.WriteLine(list.Count)
 
private void ModifyList(List<string> list)
{
   // 这里的list其实已经是一个引用副本了,但是所指向的内存地址仍然是原本方法外面的对象的,所以后面用该引用的Add方法所操作的,仍然是原本方法外面的对象的内存数据
    list.Add("1");
    list.Add("2");
    list.Add("3");
}

(2)

List<string> list=new List<string>();
ModifyList(list);
Console.WriteLine(list.Count)
 
private void ModifyList(List<string> list)
{
    list = new List<string>(); // 这里其实已经将引用指向了新的内存地址,所以后续的Add操作是在操作新对象的内存数据,而原来方法外的对象其实是没有受到影响的
    list.Add("1");
    list.Add("2");
    list.Add("3");
}

(3)

List<string> list=new List<string>();
List<string> copy = list; // 复制一个引用
ModifyList(ref list);
Console.WriteLine(copy.Count) // 复制的这个引用仍然指向原来最早的那个List
Console.WriteLine(list.Count) // list这个引用已经在ModifyList方法里被修改了,指向的是在ModifyList方法里新new出来的对象了
 
private void ModifyList(ref List<string> list)
{
    list = new List<string>(); // 因为有ref,所以这里其实已经将方法外原本的那个引用也指向了新的内存地址,所以后续的Add操作是在操作新对象的内存数据,并且方法外原本的那个引用也指向了这个新的对象
    list.Add("1");
    list.Add("2");
    list.Add("3");
}

 

 

参考:

http://www.cftea.com/c/2013/01/5724.asp

http://bbs.csdn.net/topics/390600826

相关文章
|
7月前
|
安全 C#
C# List基本用法
C# List基本用法
C# 找出泛型集合中的满足一定条件的元素 List.Wher()
在学习的过程中,发现泛型集合List有一个Where函数可以筛选出满足一定条件的元素,结合Lambda表达式使用特别方便,写出来与大家分享。 1.关于Func Func是一种有任意个输入参数,有一个返回值的委托,在使用的过程中,Func,前n-1个是输入参数类型,第N个是输出参数类型。
2088 0
|
2月前
|
C#
C#的方法的参数传递
C#的方法的参数传递
25 0
|
7月前
|
存储 C# 索引
C# | 比较IEnumerable、List、数组
IEnumerable`定义了一组用于枚举集合的方法,包括`GetEnumerator`方法,该方法返回一个实现了`IEnumerator`接口的对象,用于枚举集合中的每个元素。`List`和数组都可以使用`foreach`循环来遍历其中的元素,这是因为它们都实现了`IEnumerable`接口。 由于数组在内存中开辟了一段连续的空间,因此可以直接通过索引访问元素,访问速度很快。而 List 则需要通过指针或引用来访问元素,速度相对较慢。 由于数组的大小是固定的,当需要添加或删除元素时,需要重新创建一个新数组,将原数组中的元素复制到新数组中,并添加或删除元素。
244 0
C# | 比较IEnumerable、List、数组
C#List与ArrayList,Hashtable与Dictionary总结
C#List与ArrayList,Hashtable与Dictionary总结
53 0
C#List与ArrayList,Hashtable与Dictionary总结
|
安全 C# 索引
C# 泛型集合和非泛型集合(List ArrayLIst)
C# 泛型集合和非泛型集合(List ArrayLIst)
114 0
|
存储 安全 C#
C#里面的不同集合(数组、ArrayList集合、List泛型)
在内存中连续存储,因此可以快速而容易地从头到尾遍历元素,可以快速地修改元素
C#合并两个List并删除重复项
C#合并两个List并删除重复项
【C#】【平时练习】将左边列表框(List)的内容(月份)添加到右边列表框。最终右侧显示的内容(月份)要保持一定顺序
【C#】【平时练习】将左边列表框(List)的内容(月份)添加到右边列表框。最终右侧显示的内容(月份)要保持一定顺序
130 0
【C#】【平时练习】将左边列表框(List)的内容(月份)添加到右边列表框。最终右侧显示的内容(月份)要保持一定顺序