c# - 实例化时 List<T> 的副本

标签 c# .net

在下面的代码中,为什么 y.e[0].k 不等于 20 而不是 30? 显然发生的是 y.e[0] = x.e[0]

但我需要的是在实例化 y 时将列表从 x 复制到 y,而不仅仅是将指针 x.e 复制到 y.e;

但是:x.c 为真y.c 为假,如我所料。

感谢任何有用的评论

class Eclass {
    public int k { get; set; }
    public Eclass(int iK) { k = iK; }
}

class Sclass {

    private static int ID = -1;
    public long Id { get; set; }
    public bool c { get; set; }
    public List<Eclass> e { get; set; }

    public Sclass() {
        c = false;
        Id = ++ID;
        e = new List<Eclass>();
    }

    public Sclass(Sclass org) {
        c = org.c;
        Id = ++ID;
        //foreach (var OrgE in org.e) { e.Add(OrgE); } //also doesn't work
        //e = org.e.ToList();
        e = new List<Eclass>(org.e);
    }
}

class Program {
    static void Main(string[] args)
    {
        Console.WriteLine("steve");
        Eclass e1 = new Eclass(1);
        Eclass e2 = new Eclass(2);
        Eclass e3 = new Eclass(3);
        Eclass e4 = new Eclass(4);

        Sclass x = new Sclass();
        x.c = false;
        x.c = true;
        x.e.Add(e1);
        x.e.Add(e2);
        Sclass y = new Sclass(x);
        x.e.Add(e3);
        y.e.Add(e4);
        x.e[0].k = 10;
        y.e[0].k = 20;
        x.c = false;

        Debug.WriteLine("//{0}// //{1}// :: //{2}// //{3}//", x.c, x.e[0].k, y.c, y.e[0].k);
        x.c = !x.c;
        y.c = !y.c;
        x.e[0].k = 30;
        Debug.WriteLine("//{0}// //{1}// :: //{2}// //{3}//", x.c, x.e[0].k, y.c, y.e[0].k);
    }
}

//False// //20// :: //True// //20//

//True// //30// :: //False// //30//

最佳答案

您创建了 y使用 Sclass复制构造函数:

Sclass y = new Sclass(x);

问题是 Sclass 中的这一行复制构造函数。那就是y.e来自:

e = org.e.ToList();

这会创建一个 org.e 的副本-- 一个新的 List<Eclass> ,它引用了旧项目中的原始项目。因此,x.e[0]y.e[0] 是同一个对象.然后你给y.ex.e e2 之后每增加一项,但你从不看那些。

因为 Eclass是引用类型而不是值类型,您需要显式复制每个 Eclass列表中的实例,而不仅仅是列表本身的副本。如果你改变 Eclass来自classstruct ,副本将自动生成,因为那样它就不是引用类型了。然后你应该看到你期望的语义。 Eclass会表现得像 int k : 赋值会创建值的新副本,而不是对旧对象的新引用。

不过,更常用的方法是给出 Eclass一个克隆方法,它返回一个新的、相同的 Eclass 副本-- 或者给它一个复制构造函数,很像 Sclass 的复制构造函数.我比 Clone() 更喜欢复制构造函数因为 .NET 框架倾向于更多地使用它们,在这种情况下,您已经为 Sclass 准备好了一个。 .保持一致。

public Eclass {
    public Eclass() {}
    public Eclass(int k) {
        this.k = k;
    }
    public Eclass(Eclass org) {
        k = org.k;
    }
}

然后在 Sclass 复制构造函数中,像这样复制 e:

public Sclass(Sclass org) {
    c = org.c;
    Id = ++ID;

    //  For each item in org.e, create an identical copy, and then make a list of those. 
    e = org.e.Select(ec => new Eclass(ec)).ToList();
}

这称为“深拷贝”:它制作“根”对象的副本,并用它引用的所有引用类型对象的副本填充它。

你现在做的是一个“浅拷贝”。

关于c# - 实例化时 List<T> 的副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40407367/

相关文章:

c# - 将数据从 2 个表映射到 1 个实体 - Entity Framework 4

c# - 无法修改“System.Collections.Concurrent.ConcurrentDictionary”的返回值

c# - .NET zlib Stream 兼容 Actionscript ByteArray.uncompress

.net - 动态业务规则的架构

c# - XNA Texture2D 缓存

c# - 如何区分 'Role'接口(interface)和 'Result'接口(interface)?

C#:周围有空格!运营商,如何解读?

c# - 在 rdlc 报告中水平显示数据

c# - SSH.NET 是否只接受 OpenSSH 格式的私钥?如果没有,有什么限制?

.net - 在 DataGridViewColumn 中混合单元格类型