如何在基类中创建对象的克隆?

时间:2009-09-02 16:08:47

标签: c# inheritance

我需要一个在基类中创建对象的空克隆的方法吗?例如:

public class ChildClass : ParentClass
{
   public ChildClass()
   {
   }
}
public class ParentClass
{
  public SomeMethod()
  {
     // I want to create an instance of the ChildClass here
  }
}

到目前为止,我们在父类中定义了一个抽象方法。并且,所有子类都实现它们。但是,实现对所有人来说都是一样的,只是一种不同的类型。

public class ChildClass : ParentClass
{
   public ChildClass()
   {
   }
   public ParentClass CreateEmpty()
   {
      return new ChildClass();
   }
}
public class ParentClass
{
  public SomeMethod()
  {
     // I want to create an instance of the ChildClass here
     ParentClass empty = CreateEmpty();

  }
  public abstract ParentClass CreateEmpty();
}

有没有办法从父类中执行此操作,以便我不必为每个不同的子类继续实现相同的逻辑?请注意,可能有更多级别的继承(即ChildChildClass:ChildClass:ParentClass)。

4 个答案:

答案 0 :(得分:5)

如果使用反射不是问题,可以使用Activator类:


//In parent class
public ParentClass CreateEmpty()
{
    return (ParentClass)Activator.CreateInstance(this.GetType());
}

这将返回所需类型的空对象。请注意,此方法不需要是虚拟的。

另一方面,我认为您当前的方法非常好,几行代码并不是那么糟糕。

答案 1 :(得分:0)

这有点实验性。我不知道这是否会导致循环依赖。几个月没碰过C#。

public class ParentClass<T> where T : ParentClass<T>, new() { // fixed
    public ParentClass() {
        var x = new T(); // fixed, was T.new()
    }
}

public class ChildClass : ParentClass<ChildClass> {
    public ChildClass() { }
}

否则请去Ravadre的ReflectionCode。

答案 2 :(得分:0)

您可以对对象using the binary serializer进行深度克隆。

编辑:刚刚注意到克隆旁边的“空”这个词(我认为这是一个矛盾)。无论如何都要保留这个回复,希望它能帮助其他人找到这个问题,因为他们希望做一个普通的克隆。

答案 3 :(得分:0)

我使用以下模式。

<强>优点:

  • 这种模式确保了克隆在类的私人和公共方面的类型安全性。
  • 输出类将始终正确。
  • 你永远不会忘记覆盖“克隆”方法。 “MyDerivedClass”永远不会返回另一个类而不是“MyDerivedClass”。

<强>缺点:

  • 对于一个类,您需要创建一个接口和两个类(原型和最终)

样品:

// Common interface for cloneable classes.
public interface IPrototype : ICloneable {
    new IPrototype Clone();
}

// Generic interface for cloneable classes.
// The 'TFinal' is finaly class (type) which should be cloned.
public interface IPrototype<TFinal> where TFinal : IPrototype<TFinal> {
    new TFinal Clone();
}

// Base class for cloneable classes.
// The 'TFinal' is finaly class (type) which should be cloned.
public abstract class PrototypeBase<TFinal> : IPrototype<TFinal> where TFinal : PrototypeBase<TFinal> {
    public TFinal Clone() {
        TFinal ret = this.CreateCloneInstance();
        if ( null == ret ) {
            throw new InvalidOperationException( "Clone instance was not created." );
        }

        this.FillCloneInstance( ret );
        return ret;
    }

    // If overriden, creates new cloned instance
    protected abstract TFinal CreateCloneInstance();

    // If overriden, fill clone instance with correct values.
    protected abstract void FillCloneInstance( TFinal clone );

    IPrototype IPrototype.Clone() { return this.Clone(); }
    object ICloneable.Clone() { return this.Clone(); }
}

// Common interface for standalone class.
public interface IMyStandaloneClass : IPrototype<IMyStandaloneClass> {
    string SomeText{get;set;}
    string SomeNumber{get;set;}
}

// The prototype class contains all functionality exception the clone instance creation.
public abstract class MyStandaloneClassPrototype<TFinal> : PrototypeBase<TFinal>, IMyStandaloneClass where TFinal : MyStandaloneClassPrototype<TFinal> {
    public string SomeText {get; set;}
    public int SomeNumber {get; set}

    protected override FillCloneInstance( TFinal clone ) {
        // Now fill clone with values
        clone.SomeText = this.SomeText;
        clone.SomeNumber = this.SomeNumber;
    }
}

// The sealed clas contains only functionality for clone instance creation.
public sealed class MyStandaloneClass : MyStandaloneClassPrototype<MyStandaloneClass> {
    protected override MyStandaloneClass  CreateCloneInstance() {
        return new MyStandaloneClass();
    }
}

public interface IMyExtendedStandaloneClass : IMyStandaloneClass, IPrototype<IMyExtendedStandaloneClass> {
    DateTime SomeTime {get; set;}
}

// The extended prototype of MyStandaloneClassPrototype<TFinal>.
public abstract class MyExtendedStandaloneClassPrototype<TFinal> : MyStandaloneClassPrototype<TFinal> where TFinal : MyExtendedStandaloneClassPrototype<TFinal> {
    public DateTime SomeTime {get; set;}

    protected override FillCloneInstance( TFinal clone ) {
        // at first, fill the base class members
        base.FillCloneInstance( clone );

        // Now fill clone with values
        clone.SomeTime = this.SomeTime;
    }
}

public sealed class MyExtendedStandaloneClass : MyExtendedStandaloneClassPrototype<TFinal> {
    protected override MyExtendedStandaloneClass CreateCloneInstance() {
        return new MyExtendedStandaloneClass 
    }
}