为什么在C#中,引用型参数是隐式传递给函数的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么在C#中,引用型参数是隐式传递给函数的?相关的知识,希望对你有一定的参考价值。

所以我在学习堆栈算法的时候,我完全理解了。然而,当我看我的代码时,我并不真正理解为什么它能工作,因为在C#中,如果我想通过将参数传递给函数来改变它的值,我必须使用ref关键字,否则它是一个值型参数,当传递给函数时不应该改变。

public static class HeapSort

    public static List<int> Sort(List<int> array)
    
        List<int> result = new List<int>();
        int n = array.Count;

        for(int i = n/2 - 1; i >= 0; i--)
        
            Heapify(array, n, i);
        

        int sizeOfArray = n;
        while(result.Count != n)
        
            result.Insert(0, array[0]);
            array[0] = array[sizeOfArray - 1];
            array.RemoveAt(sizeOfArray - 1);
            sizeOfArray--;
            Heapify(array, sizeOfArray, 0);
        

        return result;
    

    private static void Heapify(List<int> array, int n, int i)
    
        int smallest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;

        if(left < n && array[smallest] > array[left])
        
            smallest = left;
        

        if(right < n && array[smallest] > array[right])
        
            smallest = right;
        

        if(smallest != i)
        
            int temp = array[smallest];
            array[smallest] = array[i];
            array[i] = temp;
            Heapify(array, n, smallest);
        

    

我不明白为什么在改变数组的时候,调用Heapify而不使用ref就可以了。

答案

在C#中,有 参考 类型和 价值 类型。值类型是通过值传递的,除非你用 ref 关键字。引用类型总是通过引用来传递。

例如,如果你像这样声明两个变量

List<int> myList = new List<int>();
int myint = 0;

myInt 有价值 0myList 只持有指向实际的 List<int>. 这意味着,当你通过 myInt 的方法,你只需要传递一个它的值的副本。当你把 myList 你做了同样的事情--你传递了它的值的副本,但它的值是一个对 List<int>因此,该参考资料的副本仍然指的是同一份资料。List<int> 的堆上。

当你在传递变量时用 ref 关键字,你实际上传递了一个指向原始变量的指针。如果你传递了 myIntref 关键字,你的方法将收到指向的指针 myInt所以它将能够修改其实际值。如果你通过 myListref 关键字同样的事情发生。现在你的方法可以修改 myList 变量。它可以将其设置为其他引用。

当你在实践中看到它时,可能会更容易理解,所以这里是一个小的控制台应用程序,显示了两个方法之间的区别,这两个方法的不同之处只在于使用了 ref 关键字

static void Main(string[] args)

    //create new instane of List<int> on the heap and store reference to it on the stack in 'myList 'variable
    List<int> myList = new List<int>()  1 ;
    //create new instance of int and store it on the stack in 'myInt' variable
    int myint = 2;

    //call MyMethod
    //copy value of myInt (2) to the new stack frame and store it in 'i' variable
    //copy value of myList (reference to List<int>) to the new stack frame and store it in 'list' variable
    MyMethod(myint, myList);
    Console.WriteLine(myint);       //prints 2
    Console.WriteLine(myList[0]);   //prints 4

    //call MyMethod
    //inside new stack frame store pointer to 'myint' variable
    //inside new stack frame store pointer to 'myList' variable
    MyMethod(ref myint, ref myList);
    Console.WriteLine(myint);       //prints 3
    Console.WriteLine(myList[0]);   //prints 5

    Console.ReadLine();


static void MyMethod(int i, List<int> list)

    //store value of 3 on stack in variable 'i'
    i = 3;
    //use reference stored on stack in 'list' variable to find our instance of List<int> on the heap and store 4 under index 0
    list[0] = 4;
    //create new instane of List<int> on the heap and store reference to it on the stack, in 'list 'variable
    list = new List<int>()  5 ;


static void MyMethod(ref int i, ref List<int> list)

    //use pointer to 'myInt' variable to store value of 3 in 'myInt' variable
    i = 3;
    //use pointer to 'myList' variable to get reference stored in it and use that reference to find our instance of List<int> on the heap and store 4 under index 0
    list[0] = 4;
    //create new instane of List<int> on the heap and use pointer to 'myList' variable to store reference to that new instance inside 'myList' variable
    list = new List<int>()  5 ;

以上是关于为什么在C#中,引用型参数是隐式传递给函数的?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA学习笔记-this隐式参数

C语言各个数据类型取值范围

可选类型的值必须被解包以引用成员,但它是隐式解包的可选属性

C++ 函数取值,它们应该取值的地方

函数与方法

c# 参数传递方式?