奇怪的方式C#将列表作为参数传递

时间:2016-08-10 22:06:47

标签: c#

所以我遇到了这个错误,其中C#表现得像我通过引用而不是通过值传递列表,就像通常那样。让我举个例子:

using System;
using System.Collections.Generic;

namespace testprogram
{
    class Program
    {
        static int x;
        static List<Coordinate> coordinates;

        static void Main(string[] args)
        {
            x = 10;
            coordinates = new List<Coordinate>();
            coordinates.Add(new Coordinate(0, 0));
            coordinates.Add(new Coordinate(1, 1));

            testfunction(x, coordinates);
            Console.WriteLine(x);
            foreach (var objekt in coordinates)
            {
                Console.WriteLine(objekt.xpos);
                Console.WriteLine(objekt.ypos);
            }
            Console.Read();
        }

        static void testfunction(int test, List<Coordinate> objects)
        {
            test = 4;

            foreach (Coordinate obj in objects)
            {
                obj.xpos = 4;
                obj.ypos = 4;
            }
        }


    }

    class Coordinate
    {
        public int xpos;
        public int ypos;

        public Coordinate(int new_x, int new_y)
        {
            xpos = new_x;
            ypos = new_y;
        }
    }
}

此代码输出:

10 
4
4
4
4

但为什么呢?我原以为:

10
0
0
1
1

我试图在Funktion中添加一个额外的List并为其分配参数的值,但即使这样也行不通。有没有解决方法呢?

3 个答案:

答案 0 :(得分:1)

List<T>参数是一个通过值传递的引用类型。

如果修改方法中列表中的任何项目,则在离开方法时这些项目将保持更改。

但是,如果重新分配方法内的引用,则这些更改将在方法外部丢失。如果您想通过引用传递参数,请使用ref关键字:

static void testfunction(int test, ref List<Coordinate> objects)
{
    // This will update objects outside the testfunction method
    objects = new List<Coordinate>();
}

您还可以使用out关键字,该关键字与ref关键字类似。唯一的区别是,在调用方法之前,您不必初始化作为out参数传递的值,并且在离开方法之前必须初始化它们。< / p>

static void Main(string[] args)
{
    // No need to initialise variable passed as "out" parameter
    List<Coordinate> objects;
    testfunction(test, out objects);
}

static void testfunction(int test, out List<Coordinate> objects)
{
    // Removing this line would result in a compilation error
    objects = new List<Coordinate>();
}

答案 1 :(得分:0)

您通过值&#34;传递了对列表&#34;的引用。所以,如果你改变参考&#34;对象&#34;在&#34; testfunction&#34;,然后&#34;坐标&#34;不会改变(作为指针)。但改变&#34;对象&#34;的元素。会影响&#34;坐标&#34;。

的元素

答案 2 :(得分:0)

你的期望是错误的。该列表作为值传递。这意味着名为template <class T> union const_cast_impl { using CT = const T; static_assert(std::is_same<CT,const int *>::value, "CT is not const int*"); T data; CT cdata; const_cast_impl(CT ptr):cdata(ptr){} operator T(){ return data; } }; int main(){ int a = 2; const int *ptr = &a; int *ptr2 = const_cast_impl<int *>(ptr); } 的变量是原始列表变量的值副本。但是列表包含引用,我的意思是列表的内容是对objects个对象的引用。因此,如果您尝试更改Coordinate之类的列表变量,则不会更改原始列表。但是,如果更改列表中的对象,则更改实际应用于原始列表。

objects = new List<>()

这两个示例都会更改原始列表。

如果您希望安全地更改列表中的任何内容,则必须对其进行深层克隆。您可以使用Clone()方法,但这可能很棘手,因为您必须手动克隆列表中的每个对象。这已在这里得到解答: How create a new deep copy (clone) of a List<T>?