【问题标题】:How to clone a generic list of instances of a class derived from an abstract class in C#?如何克隆从 C# 中的抽象类派生的类的通用实例列表?
【发布时间】:2011-09-07 20:41:26
【问题描述】:

我有一个基类:abstract class Base 和一些派生类:class Derived: Base,所有数据成员都在基类中。我还有另一个通用列表:List<Base> list。现在我要对列表执行Clone() 操作。我读过this thread,但发现我的情况有点复杂。由于基类是抽象的,所以列表的元素不能通过复制构造函数或实现ICloneable接口来克隆。但是由于所有数据成员都在基类中,因此一次又一次地编写相同的代码用于在派生类中克隆将是多余的。完成这项工作的最佳方法是什么?感谢您提供提示。

更新:附上简化的源代码

public class Point : ICloneable
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    { X = x; Y = y; }

    public Point(Point p)
    {
        X = p.X; Y = p.Y;
    }

    public object Clone()
    {
        return MemberwiseClone();
    }
}

public abstract class ObjectThatHasPosition : ICloneable
{
    public Point CurrentPosition { get; set; }
    public ObjectThatHasPosition(Point p)
    { CurrentPosition = new Point(p); }
    public object Clone()
    {
        return MemberwiseClone();
    }
}

public class Man : ObjectThatHasPosition
{
    public Man(Point p) : base(p) { }
}

static class Extensions
{
    public static List<ObjectThatHasPosition> Clone(this List<ObjectThatHasPosition> src)
    {
        List<ObjectThatHasPosition> dst = new List<ObjectThatHasPosition>(src.Count);
        src.ForEach((item) => { dst.Add((ObjectThatHasPosition)item.Clone()); });
        return dst;
    }
}

    static void Main(string[] args)
    {
        List<ObjectThatHasPosition> firstList = new List<ObjectThatHasPosition>();
        firstList.Add(new Man(new Point(0, 0)));
        List<ObjectThatHasPosition> anotherList = firstList.Clone();
        firstList[0].CurrentPosition.X = 1;
    }

可以看到两个列表的元素是相同的。

【问题讨论】:

  • 请解释为什么“不能通过...实现 ICloneable 接口进行克隆”。抽象类中没有任何东西可以阻止接口的实现(即,如果你想强制派生类实现它,可以通过抽象函数......)
  • 我认为 Clone() 必须调用复制构造函数,所以...
  • 你也可以在 Base 中实现一个拷贝构造函数,可以通过继承的类构造函数调用。也没有什么可以阻止的。

标签: c# clone abstract-class generic-list


【解决方案1】:

我不明白为什么Base 不能实现ICloneable

public abstract class Base : ICloneable
{
    public object Clone()
    {
        return MemberwiseClone();
    }
}

当在派生类上调用时,它仍然会返回正确的实例(即与现有对象相同的类型)。派生类中的任何字段也将被复制——尽管是以一种浅显的方式。举个具体的例子:

using System;

public abstract class BaseClass : ICloneable
{
    public object Clone()
    {
        return MemberwiseClone();
    }
}

public class Derived : BaseClass
{
    private readonly string name;

    public Derived(string name)
    {
        this.name = name;
    }

    public override string ToString()
    {
        return "Derived with name " + name;
    }
}

class Test
{
    static void Main(string[] args)
    {
        BaseClass b = new Derived("fred");

        object clone = b.Clone();
        Console.WriteLine(clone.ToString());
    }
}

编辑:我怀疑你想要类似的东西:

public abstract class ObjectThatHasPosition : ICloneable
{
    public Point CurrentPosition { get; set; }
    public ObjectThatHasPosition(Point p)
    {
        CurrentPosition = p; 
    }

    public object Clone()
    {
        var clone = (ObjectThatHasPosition) MemberwiseClone();
        clone.CurrentPosition = (Point) CurrentPosition.Clone();
    }
}

【讨论】:

  • 但是我的代码还是不行,看不出问题出在哪里(附源码)。
  • @ziyuang:您希望MemberwiseClone 制作一个deep 副本吗?它没有。如果你想要一个除了浅拷贝之外的任何东西,你需要自己做那部分。查看我的编辑。
  • 我觉得可以写一个递归版的 MemberwiseClone 通过反射机制做深拷贝。
  • @ziyuang:是的,有可能。但在大多数情况下,这将是矫枉过正 - 最好在子类中覆盖 Clone 并明确克隆您真正想要克隆的成员。
猜你喜欢
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-26
相关资源
最近更新 更多