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

问题描述 投票:0回答:1

所以我在学习堆栈算法的时候,我完全理解了。然而,当我看我的代码时,我并不真正理解为什么它能工作,因为在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# value-type reference-type
1个回答
1
投票

在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 };
}
© www.soinside.com 2019 - 2024. All rights reserved.