当我尝试加载列表时,我的值完全相同

时间:2016-07-24 21:00:57

标签: c# list

我有一个简单的课程:

private class ColumnAndValue
{
    private string columnName;
    private string columnValue;

    public string ColumnName
    {
        get { return columnName; }
        set { columnName = value.Trim(); }
    }
    public string ColumnValue
    {
        get { return columnValue; }
        set { columnValue = value.Trim(); }
    }
}

该班级列表:

private List<ColumnAndValue> cvList = new List<ColumnAndValue>();

这是我的问题所在,当我尝试加载列表时,我的值就会出现。这是我加载它的方式:

public void TestList()
{
    ColumnAndValue cv = new ColumnAndValue();
    cv.ColumnName = "Column 1";
    cv.ColumnValue = "Value 1";
    cvList.Add(cv);

    cv.ColumnName = "Column 2";
    cv.ColumnValue = "Value 2";
    cvList.Add(cv);

    cv.ColumnName = "Column 3";
    cv.ColumnValue = "Value 3";
    cvList.Add(cv);

    cv.ColumnName = "Column 4";
    cv.ColumnValue = "Value 4";
    cvList.Add(cv);

    List<string> c1 = new List<string>();

    c1 = cvList.Select(c => c.ColumnName).ToList();

    foreach (object obj in c1)
    {
        Console.WriteLine(obj.ToString());
    }

}

当我运行此代码时,我得到四次迭代:

Column 4
Column 4
Column 4
Column 4

当我在调试时进入每个cvList.Add时,第一次迭代显示带有正确信息的cvList,第二次两个值都有第2列......所以,我试过这样:

ColumnAndValue cv1 = new ColumnAndValue();
ColumnAndValue cv2 = new ColumnAndValue();
ColumnAndValue cv3 = new ColumnAndValue();
ColumnAndValue cv4 = new ColumnAndValue();

cv1.ColumnName = "Column 1";
cv1.ColumnValue = "Value 1";
cvList.Add(cv1);

cv2.ColumnName = "Column 2";
cv2.ColumnValue = "Value 2";
cvList.Add(cv2);

cv3.ColumnName = "Column 3";
cv3.ColumnValue = "Value 3";
cvList.Add(cv3);

cv4.ColumnName = "Column 4";
cv4.ColumnValue = "Value 4";
cvList.Add(cv4);

一切都按预期发布:

Column 1
Column 2
Column 3
Column 4

我的问题是,如何只使用一个cv实例填充列表?

6 个答案:

答案 0 :(得分:3)

将其更改为:

public void TestList()
{
    cvList.Add(new ColumnAndValue(){ColumnName = "Column 1", ColumnValue = "Value 1"});
    cvList.Add(new ColumnAndValue(){ColumnName = "Column 2", ColumnValue = "Value 2"});
    cvList.Add(new ColumnAndValue(){ColumnName = "Column 3", ColumnValue = "Value 3"});
    cvList.Add(new ColumnAndValue(){ColumnName = "Column 4", ColumnValue = "Value 4"});

    List<string> c1 = cvList.Select(c => c.ColumnName).ToList();

    foreach (object obj in c1)
    {
        Console.WriteLine(obj.ToString());
    }

}

因为List.Add()添加对ColumnAndValue实例的引用而不是副本,因此,如果更改对象的名称,它将在您使用它的所有位置更改。

您可以在MSDN上的When is a C# value/object copied and when is its reference copied?Value Types and Reference Types

了解更多相关信息

答案 1 :(得分:2)

每次都需要新建你的简历

public void TestList()
    {
        ColumnAndValue cv = new ColumnAndValue();
        cv.ColumnName = "Column 1";
        cv.ColumnValue = "Value 1";
        cvList.Add(cv);

cv = new ColumnAndValue();
        cv.ColumnName = "Column 2";
        cv.ColumnValue = "Value 2";
        cvList.Add(cv);

cv = new ColumnAndValue();
        cv.ColumnName = "Column 3";
        cv.ColumnValue = "Value 3";
        cvList.Add(cv);

cv = new ColumnAndValue();
        cv.ColumnName = "Column 4";
        cv.ColumnValue = "Value 4";
        cvList.Add(cv);

        List<string> c1 = new List<string>();

        c1 = cvList.Select(c => c.ColumnName).ToList();

        foreach (object obj in c1)
        {
            Console.WriteLine(obj.ToString());
        }

    }

cv是对象的句柄。如果你不是每次都新建它,你只是改变同一个对象的值。你的cvlist只引用了同一个对象,每次都会更新

答案 2 :(得分:2)

发生的事情是,您的List实际上是您已创建的同一对象的引用列表。您不断更改同一对象中的数据,但不断在列表中添加对它的引用。

有关详细信息,请check the difference between reference types and value types

编辑:这个效果有一个答案,但由于某种原因被删除了。您期望的行为是值类型,它是使用struct关键字定义的。值类型按值复制。因此,在您的代码中,将class更改为struct会执行您期望的行为。 请记住它仍然是奇怪的代码,您应该习惯使用新数据实现新对象,因为您的代码将更具可读性。改变现有对象中的数据(即Mutability)的能力是一个强大的工具,但是如你刚才发现的那样,使用它很容易被滥用和出错。

答案 3 :(得分:1)

您应该使用新实例。如果您将项目添加到列表,然后更改项目属性,您只是编辑相同的项目。再次将其添加到列表中只会添加对该项目的另一个引用。

这是一种简单的方法:

private class ColumnAndValue
{
    private string columnName;
    private string columnValue;

    public string ColumnName
    {
        get { return columnName; }
        set { columnName = value.Trim(); }
    }
    public string ColumnValue
    {
        get { return columnValue; }
        set { columnValue = value.Trim(); }
    }
    public ColumnAndValue(string colName, string colValue)
    {
       columnName = colName;
       columnValue = colValue;
    }
}

然后使用以下方式创建列表:

private List<ColumnAndValue> cvList = new List<ColumnAndValue>();
cvList.Add(new ColumnAndValue("Column 1", "Value 1"));
cvList.Add(new ColumnAndValue("Column 2", "Value 2"));
cvList.Add(new ColumnAndValue("Column 3", "Value 3"));
cvList.Add(new ColumnAndValue("Column 4", "Value 4"));

答案 4 :(得分:1)

您看,ListT.Add方法不会创建其引用参数的副本。它只是复制并存储对您的类(相同)实例的引用四次。

这是ListT.Add referencesource.microsoft.com

的代码

您的问题是矛盾的,如果您只想要一个实例,那么您只能获得一个实例。 ListT.Add不复制(不创建引用类型的实例)。

答案 5 :(得分:1)

将cv对象添加到列表中时,列表会为该对象维护引用

这意味着您反复将同一个对象添加到列表中,并更改同一个对象。

您要做的是在列表中添加不同的变量:

public void TestList()
{
    ColumnAndValue cv = new ColumnAndValue();
    cv.ColumnName = "Column 1";
    cv.ColumnValue = "Value 1";
    cvList.Add(cv);

    // Now cv is a reference to a different object
    cv = new ColumnAndValue();
    cv.ColumnName = "Column 2";
    cv.ColumnValue = "Value 2";
    cvList.Add(cv);

    // Now cv is a reference to a different object
    cv = new ColumnAndValue();
    cv.ColumnName = "Column 3";
    cv.ColumnValue = "Value 3";
    cvList.Add(cv);

    // Now cv is a reference to a different object
    cv = new ColumnAndValue();
    cv.ColumnName = "Column 4";
    cv.ColumnValue = "Value 4";
    cvList.Add(cv);

    List<string> c1 = new List<string>();

    c1 = cvList.Select(c => c.ColumnName).ToList();

    foreach (object obj in c1)
    {
        Console.WriteLine(obj.ToString());
    }

}