C#容器通过引用或值初始化?

And*_*ell -2 c# containers reference

我对C++很有经验,但对C#来说有点新鲜.

将对象添加到容器时,它们是通过引用还是按值传递的?

也就是说,如果我这样做:

myClass m = new myClass(0);       //Assume the class just holds an int
List<myClass> myList = new List<myClass>(1);
myList.Add(m);
myList[0] += 1;
Console.WriteLine(m);
Console.WriteLine(myList[0]);
Run Code Online (Sandbox Code Playgroud)

结果会是:

0
1
Run Code Online (Sandbox Code Playgroud)

还是会的?

1
1
Run Code Online (Sandbox Code Playgroud)

如果是前者,那怎么能让我做到后者呢?我的第一直觉是做类似的事情

myClass ref mref = m; 
Console.WriteLine(mref);
Run Code Online (Sandbox Code Playgroud)

但这似乎不是有效的语法.

Oli*_*bes 6

该值通过值传递给Add方法; 但是,如果传递引用类型(类始终是引用类型),则值本身是引用.所以问题不在于值是通过值还是通过引用传递,而是类型是值类型还是引用类型.

class MyClass
{
    public int Number { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

通过此声明,我们得到:

MyClass m = new MyClass();
List<MyClass> myList = new List<MyClass>();
myList.Add(m);

myList[0].Number += 1;
Console.WriteLine(myList[0].Number); // Displays 1
Console.WriteLine(m.Number); // Displays 1

myList[0].Number += 1;
Console.WriteLine(myList[0].Number); // Displays 2
Console.WriteLine(m.Number); // Displays 2
Run Code Online (Sandbox Code Playgroud)

请注意,这不适用于a struct,因为返回的值myList[0]将是存储在列表中的值的副本.将+= 1只会递增Number该临时副本的属性,因而具有比消耗几个处理器周期没有其他作用.因此,仅创建不可变结构是一个很好的建议.


如果要直接显示对象,请覆盖 ToString

class MyClass
{
    public int Number { get; set; }

    public override string ToString()
    {
        return Number.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,你可以写

myList[0].Number += 1;
Console.WriteLine(myList[0]);
Console.WriteLine(m);
Run Code Online (Sandbox Code Playgroud)

您甚至可以myList[0] += 1使用操作员超载来完成工作.在MyClass声明

public static MyClass operator +(MyClass m, int i) 
{
    m.Number += i;
    return m;
}
Run Code Online (Sandbox Code Playgroud)

但这有点奇怪,除非你的类代表一个数字,但在这种情况下,一个不可变的struct首选,因为数字通常被认为是不可变的值类型.

public static MyStruct operator +(MyStruct m, int i) 
{
    return new MyStruct(m.Number + i);
}
Run Code Online (Sandbox Code Playgroud)