浅谈值类型和引用类型在堆和栈中的存储二

断了今生、忘了曾经 提交于 2020-04-03 23:35:56

前一篇我们浅谈了“堆”和“栈”,这篇文章我们主要谈一下值类型和引用类型在作为参数传递时候,有什么不同。

主要分为两种情况:

1.传递值类型(Passing Value Types)

2.传递引用类型(Passing Reference Types)

 

首先我们来看一下第一种情况,传递值类型(Passing Value Types)

public void Go()
{
     var x = 5;
     AddFive(x);
     Console.WriteLine(x.ToString());
}

public int AddFive(int pValue)
{
     pValue += 5; 
     return pValue;
}

上一篇文章我们已经讨论过关于值类型存储的问题,所以这里不再过多叙述。

我们都知道,值类型使用的就是数据本身,所以5会被拷贝到pValue。所以最终x的值还是不会改变。

需要谨记的是,如果我们将一个非常大的值类型变量(如一个很大的struct)复制到“栈“上,这对内存空间和处理器处理周期的消耗是很大的,因为”栈“空间并非无限的。

如何解决这种效率低的问题呢?先别慌,让我们来看一个例子。

public void Go()
{
    MyStruct x = new MyStruct();
    DoSomething(ref x);
}

public struct MyStruct
{
    long a, b, c, d, e, f, g, h, i, j, k, l, m;
}

public void DoSomething(ref pValue)
{
    // DO SOMETHING HERE....
}

看到没有,DoSomething()方法有一个ref关键字。这就引入了我们在传递值类型的另外一种情况,值类型按照引用传递。

看到没有,这个时候的pValue就是一个指向x的一个地址指针。

需要小心的是,当我们用引用的方法传递一个值参数时,我们访问的是源参数本身。任何对pValue的改变都是对x的改变。下面这段代码,会使x.a改变为12345。

public void Go()
{
    MyStruct x = new MyStruct(); 
    x.a = 5;
    DoSomething(ref x);
    Console.WriteLine(x.a.ToString());
}

public voidDoSomething(ref MyStructpValue)
{
    pValue.a = 12345;
}

 

 

 接下来我们来看看另外一种情况,传递引用类型(Passing Reference Types)

public class MyInt
{
    public int MyValue;
}

public void Go()
{
    var x = new MyInt();
    x.MyValue = 2;
    DoSomething(x);
    Console.WriteLine(x.MyValue.ToString());
}

public void DoSomething(MyInt pValue)
{
    pValue.MyValue = 12345;
}

最终会输出12345,发现结果已经被改变。将x的值(位于“堆“上的 MyInt 对象的地址)拷贝至pValue,使x和pValue同时指向MyInt对象的地址。

既然值类型可以使用ref关键字,那么引用类型在使用ref关键字的情况下,又是怎么一回事呢?好的,我们同样来看一个例子:

public class Thing
{

}

public class Animal:Thing
{
    public int Weight;
}

public class Vegetable:Thing
{
    public int Length;
}

public void Go()
{
    Thing x = new Animal();
    Switcharoo(ref x);
    Console.WriteLine("x is Animal:"+ (x is Animal).ToString());
    Console.WriteLine("x is Vegetable:" + (x is Vegetable).ToString());
}

public void Switcharoo(ref Thing pValue)
{
    pValue = new Vegetable();
}

最后程序执行的结果是:

x is Animal:False

x is Vegetable:True

pValue这次是指向x的,然后通过改变x的地址,使得pValue也发生改变。

 

 

好了,暂时就介绍到这里,如果有什么疑问,或者有误的地方,欢迎大家指点和交流。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!