【问题标题】:does passing a collection to a function means the function can change the collection's elements?将集合传递给函数是否意味着该函数可以更改集合的元素?
【发布时间】:2015-03-06 14:58:15
【问题描述】:

我实际上知道问题的答案(我认为),但我不知道原因......

所以,我知道如果我有类似以下的课程:

class Man
{
    public string Name;
    public int Height;

    public Man() { }
    public Man(string i_name, int i_height)
    {
        Name = i_name;
        Height = i_height;
    }

}    

我有以下程序类(带有主函数):

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        Man g = new Man("greg", 175);

        //assigning null to g inside the function.
        p.ChangeMan(g);


        Console.WriteLine(g == null? "the function changed g out side the function" : "the function did not change g out side the function");
        //the output of course is that the function did not change g outside the function.

        //now I am creating a list of Man and adding 5 Man instances to it.

        List<Man> manList = new List<Man>();
        for (int i = 0; i < 5; i++)
        {
            manList.Add(new Man("Gadi" + i.ToString(), 10 * i));
        }

        //assigning null to the list insdie the function
        p.ChangeList(manList);
        Console.WriteLine(manList == null ? "the function changed the list out side the function" : "the function did not change the list out side the function");
        //the output of cousre again is the function did not change the list out side the function

        //now comes the part I dont understand...


        p.ChangeManInAList(manList);

        Console.WriteLine("list count = " + manList.Count());
        //count is now 6.

        Console.WriteLine(manList[0] == null ? "the function changed the element out side the function" : "the function did not change the element out side the function");
        //the out again - the function did not change...


    }

    public void ChangeMan(Man g)
    {
        g = null;
    }

    public void ChangeManInAList(IList<Man> gadiList)
    {
        Man g = gadiList.First<Man>();
        g = null;
        Console.WriteLine(g == null? "g is null" : "g is not null");

        gadiList.Add(new Man("a new gadi", 200));
        Console.WriteLine("list count = " + gadiList.Count());
    }

    public void ChangeList(List<Man> list)
    {
        list = null;
    }


}

我将 null 分配给列表的第一个元素 + 将一个 Man 添加到列表中。我希望如果我可以添加到列表中,我也可以更改元素,但我看到了不同的......

我能够将一个 Man 添加到列表中,但无法将 null 分配给其中一个元素,为什么?我知道列表是按值传递的,所以我不能更改列表本身(比如将 null 分配给它),但我可以添加它吗?并且不能将 null 分配给元素?它们也被 val 传递了吗?

会很高兴得到一些好的和清晰的解释:)

【问题讨论】:

  • "Console.WriteLine(g == null ?"函数改变了列表"不应该是"Console.WriteLine(manList == null ?"函数改变了列表"?
  • 是的,你是对的,但是输出是一样的:)
  • 当您执行g = null 时,您不会将g 引用的Man 引用 更改为null,您只是在设置局部变量gnull 所以它不再指代原来的Man。这不会影响Man 或包含它的List
  • 看它就像一根绳子上的氦气球。您已经掌握了字符串(您的参考变量)。您将字符串显示给您的朋友(函数),他跟随字符串直到气球(对象实例)并将他自己的字符串与它(参数变量)联系起来。然后你的朋友剪断他的字符串(将 null 分配给他的变量)。这不会影响您的绳子或气球。您的朋友根本没有附加任何字符串。

标签: c# .net pass-by-reference pass-by-value


【解决方案1】:

这是你的困惑点:

 Man g = gadiList.First<Man>();
 g = null;

您实际上所做的是从列表中获取Man 并将其分配给局部变量g
然后,为变量 g 分配一个不同的值。

您在这里没有更改任何列表成员的值,您只是更改了变量g 所指的值。

让我们尝试将它与这个例子进行比较:

int a = 5;
int b = a;
b = 3;
//you wouldn't expect `a` to be 3 now, would you?

为了更改列表项的值,您需要将列表索引显式设置为不同的值:

Man g = gadiList.First<Man>();
gadiList[gadiList.IndexOf(g)] = null;

//or specifically in this case:
gadiList[0] = null;

【讨论】:

  • 这导致了另一个问题:所以,我看到我可以使我的元素无效,我有办法保护它吗?我不希望为我提供功能的用户意外地使我的元素无效...
  • @JimmyBoy 查看ReadOnlyCollection
  • @JimmyBoy 你什么意思?您只能通过 gadiList[i] = null; 来“清空您的元素”
  • 我有一个问题 - 为什么在 ChangeMan 方法中分配 null 不会改变 Main 方法中的 g 变量,而如果我们把 g.Name = "greg2" 放在那里它会?
  • @Rotem - 谢谢,我确实更改了我的代码并看到了你的意思,我的错误(愚蠢的错误)我将阅读有关 readOnlyCollection :) 听起来像我正在寻找的东西。再次感谢
【解决方案2】:

当您从列表中获取元素时,您将获得对列表项的新引用。 因此,您得到两个引用:一个(列表对象中的私有引用),您的引用。 当您将引用设置为 null 时,它不会影响列表对象中的引用。您的引用变为空,但私有列表引用保持不变。

【讨论】:

    猜你喜欢
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 2021-07-15
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多