为什么列表在没有引用的情况下传递给像ref一样传递的函数?

如果我没有得到这个可怕的错误,这种行为对我来说很奇怪。 而不是解释,我会在下面发布一个示例代码,请告诉我为什么我会得到输出x而不是y。

    private void button1_Click(object sender, EventArgs e)
    {
        List<int> l = new List<int>() { 1, 2, 3 };
        Fuss(l);
        MessageBox.Show(l.Count.ToString());
    }

    private void Fuss(List<int> l)
    {
        l.Add(4);
        l.Add(5);
    }

输出应该,我假设将是3.但我得到的输出为5.我知道输出可以是5,如果我这样做:

    private void button1_Click(object sender, EventArgs e)
    {
        List<int> l = new List<int>() { 1, 2, 3 };
        Fuss(ref l);
        MessageBox.Show(l.Count.ToString());
    }

    private void Fuss(ref List<int> l)
    {
        l.Add(4);
        l.Add(5);
    }

它不像它通过参考。

void ChangeMe(List<int> list) {
  list = new List<int>();
  list.Add(10);
}
void ChangeMeReally(ref List<int> list) {
  list = new List<int>();
  list.Add(10);
}

尝试一下。 你注意到了区别吗?

如果你在没有引用的情况下传递它,你只能改变列表的内容(或者任何引用类型)(因为正如其他人所说的那样,你正在传递一个引用到堆上的对象并因此改变相同的“内存”)。

但是,您不能更改“列表”,“列表”是指向List类型的对象的变量。 只有通过引用传递它才能更改“列表”(使其指向其他位置)。 你会得到一份参考文献,如果改变了,只能在你的方法中观察到。


参数是通过C#中的值传递的,除非它们用refout修饰符标记。 对于引用类型,这意味着引用是按值传递的。 因此,在Fussl指的是List<int>的同一个实例作为其调用者。 因此,对这个List<int>实例的任何修改都会被调用者看到。

现在,如果用refout标记参数l ,那么该参数将通过引用传递。 这意味着在Fussl是存储位置的别名,用作调用该方法的参数。 要清楚:

public void Fuss(ref List<int> l)

由...调用

List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);

现在,在Fussllist的别名。 特别是,如果将一个新的List<int>实例分配给l ,则调用者也会看到分配给变量list新实例。 特别是,如果你说

public void Fuss(ref List<int> l) {
    l = new List<int> { 1 };
}

那么调用者现在将看到一个包含一个元素的列表。 但如果你说

public void Fuss(List<int> l) {
    l = new List<int> { 1 };
}

并通过

List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);

那么调用者仍然会看到list有三个元素。

明确?


像List这样的引用类型的ref和non-ref之间的差异不是你是否传递引用(总是会发生),而是引用是否可以改变。 尝试以下操作

private void Fuss(ref List<int> l)
{
    l = new List<int> { 4, 5 };
}

你会看到count是2,因为这个函数不仅操纵了原始列表,而且还引用了它本身。

链接地址: http://www.djcxy.com/p/3561.html

上一篇: Why is list when passed without ref to a function acting like passed with ref?

下一篇: Easiest way to convert int to string in C++