instanciation

时间:2016-11-03 17:05:10

标签: 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 //

2 个答案:

答案 0 :(得分:4)

您使用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.e之后的每个附加项目都会x.ee2,但您永远不会看到这些项目。

由于Eclass是引用类型而不是值类型,因此您需要在列表中显式创建每个Eclass实例的副本,而不仅仅是列表本身的副本。如果您将Eclassclass更改为struct,则会自动生成副本,因为它不会成为引用类型。然后你应该看到你期望的语义。 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();
}

这被称为&#34;深拷贝&#34;:它制作了&#34; root&#34;的副本。 object,并使用它引用的所有引用类型对象的副本填充它。

你现在正在做的是一个&#34;浅拷贝&#34;。

答案 1 :(得分:-1)

阅读评论。您将看到该信用证属于@EdPlunkett

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

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;
        e = org.e.Select(ec => new Eclass(ec)).ToList();
    }
}

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);
    }
}