实现自定义克隆/复制功能:抽象还是接口?

时间:2013-08-05 18:20:01

标签: c# interface abstract-class icloneable

由于我已经了解到不建议实现ICloneabledue to the fact that it does not differentiate between Deep Copy or Shallow Copy),我正在尝试确定是将其实现为抽象还是接口。

我觉得我的实施方式基本保持不变,例如一个binary deep copy和一个MemberwiseClone shallow copy,所以为此我觉得抽象方法是理想的。但是,我的理解是C#不进行多重继承,因此如果我需要使用另一个抽象类,那么我就不再可以了。

在这种情况下,我觉得实现自定义ICloneable(例如ICustomCloneable)将是更好的选择,但如果实现在许多类中实际上是相同的,我觉得我是没有充分利用代码重用。

话虽这么说,使用接口来保持抽象继承在我的可复制类中更重要的事情是有效的吗?或者还有另一种方法吗?

或者,抽象实现另一个抽象是否有效(读:不臭)?这是我猜测绕过单一继承,阻止我实现CloneCapable类以及另一个抽象,但听起来它可能是有问题的。 e.g:

public abstract class CloneCapable
{
  public object ShallowCopy()
  {
    // implementation
  }

  public object DeepCopy()
  {
    // implementation
  }
}

public abstract class ClassA : CloneCapable {}

// abstract-abstract since I can't do ClassB : ClassA, CloneCapable
public abstract class ClassB : ClassA {} 

2 个答案:

答案 0 :(得分:2)

我肯定会把它变成一个界面。原因是,接口应该是非常通用的,这就是我们可以实现多个接口的原因。如果你想编写一些样板代码,那么就没有什么可以阻止你利用接口和抽象类了。

public interface ICustomCloneable<T>
{
    T ShallowCopy();
    T DeepCopy();
}

public abstract class CustomCloneable<T> ICustomCloneable<T> where T : class
{
    public T ShallowCopy() { return ShallowCopy(this); }
    public T DeepCopy() { return DeepCopy(this); }

    // static helpers
    public static object ShallowCopy(T obj) { /* boilerplate implementation */ }
    public static object DeepCopy(T obj) { /* boilerplate implementation */ }
}


public class ClassA : CustomCloneable<ClassA> { /* Use boilerplate functionality */ }
public class ClassB : SomeOtherClass, ICustomCloneable<ClassB>
{
    // implement ICustomCloneable using static helpers
    public ClassB ShallowCopy() { return CustomCloneable<ClassB>.ShallowCopy(this); }
    public ClassB DeepCopy() { return CustomCloneable<ClassB>.DeepCopy(this); }
}

我在这里使用过泛型,但是没有理由你需要......甚至可能不希望这样做。这种方法允许您编写样板代码,但不能将其绑定

public class ClassC : ICustomCloneable<ClassC>
{
    public ClassC ShallowCopy() { /* Do special cloning for ClassC */ }
    public ClassC DeepCopy() { /* Do special cloning for ClassC */ }
}

答案 1 :(得分:0)

我在想创建一个界面是可行的方法,但后来我找到了this问题和第一个答案。这是进行克隆的一种很好的方法,但我认为使用Custom Extension Method可能会很顺利,所以我根据第一篇文章和MS帮助页面中的代码编写了以下代码:

可以使用的一些课程:

[Serializable]
public abstract class Base
{
    public abstract int m1();
}

[Serializable]
public class derived : Base
{
    public int a = 42;
    public override int m1()
    {
        throw new NotImplementedException();
    }
}

具有基于来自两个链接的代码示例的扩展方法的类

//Extension methods must be defined in a static class 
public static class StringExtension
{
    // This is the extension method. 
    // The first parameter takes the "this" modifier
    // and specifies the type for which the method is defined. 
    public static T MyCloneExtension<T>(this T t)
    {
        // Code in this function was copied from https://stackoverflow.com/questions/78536/deep-cloning-objects-in-c-sharp
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(t, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, t);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
}

最后调用克隆对象

derived d = new derived();
derived d2 = d.MyCloneExtension<derived>();