通过基类创建派生类的实例,无需硬编码

我的问题如下:

我有一个需要抽象的基类。 它有几个派生类,每个派生类都有自己的特殊属性,这些属性包含在Properties成员中。

我需要能够创建这些派生类之一的新实例,以便所有成员都是等效的,但修改新实例不会修改原始实例。

最后,我想在不必在基类的每个派生类型中进行硬编码的情况下执行此操作。 (诚​​然,这将是最简单的解决方案,但这不是重点)

所有派生类都满足与基类的“is-a”关系。

这是代码:

public abstract class BaseClass { //Default properties here int x, y, z, ...; //Custom made class to hold custom properties protected Attributes Properties; public BaseClass createNewInstance() { return createNewInstanceStep1(); } //Each derived class implements their own version of this, //to handle copying any custom members contained in Properties. protected abstract BaseClass createNewInstanceStep2(); protected BaseClass createNewInstanceStep1() { BaseClass newInstance = new BaseClass(); // <- Doesn't work because class is abstract //Copy default properties newInstance.x = x; newInstance.y = y; newInstance.z = z; //Call the new instance's step 2 method, and return the result. return newInstance.createNewInstanceStep2(); } } 

这段代码的问题是BaseClass newKeyFrame = new BaseClass(); 线。 由于类是抽象的,因此无法创建它的实例。

问题是我需要能够调用派生类的任何类型的构造函数,因为它们在其构造函数中都有不同的代码,无法共享。

我听说使用Reflection可能是一个可行的解决方案,但我不知道如何。

如何在不必为每个派生类型的情况下进行硬编码的情况下解决这个问题?

您可以使createNewInstanceStep1通用。 我还修改了Step2void类型(我希望它能修改当前实例,所以返回总是会return this;无论如何),因为否则我不会真正理解我喜欢的方式在这里使用它。 如果像这样改变它是没有意义的,那么我只使这种方法通用的整个方法都行不通。

createNewInstance现在使用reflection调用等效的return createNewInstanceStep1();

 public BaseClass createNewInstance() { var method = typeof(BaseClass).GetMethod("createNewInstanceStep1", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(this.GetType()); var value = method.Invoke(this, null); return (BaseClass)value; } //Each derived class implements their own version of this, //to handle copying any custom members contained in Properties. protected abstract void createNewInstanceStep2(); protected T createNewInstanceStep1() where T : BaseClass, new() { T newInstance = new T(); // works! //Copy default properties newInstance.x = x; newInstance.y = y; newInstance.z = z; //Call the new instance's step 2 method, and return the result. newInstance.createNewInstanceStep2(); return newInstance; } 

如果这不起作用,另一种方法是自引用generics类型 。 不过要避免这种情况是件好事,因为它令人困惑,整体而言并不是一个好的设计。

 public sealed class SubClass : BaseClass { protected override SubClass createNewInstanceStep2() { Console.WriteLine("In step 2"); return this; } } public abstract class BaseClass where T : BaseClass, new() public T createNewInstance() { return createNewInstanceStep1(); } //Each derived class implements their own version of this, //to handle copying any custom members contained in Properties. protected abstract T createNewInstanceStep2(); protected T createNewInstanceStep1() { T newInstance = new T(); ... 

让派生类进行新实例的实例化有什么问题?

 public abstract class BaseClass { //Default properties here int x, y, z, ...; //Custom made class to hold custom properties protected Attributes Properties; public abstract BaseClass createNewInstance(); protected void CopyData(BaseClass original) { this.x = original.x; this.y = original.y; this.z = original.z; } } public class ChildClass : BaseClass { public BaseClass createNewInstance() { ChildClass newInstance = new ChildClass(); newInstance.CopyData(this); // Do any additional copying return newInstance; } } 

您可以使createNewInstanceStep1成为受保护的void init方法,该方法启动此对象,并在每个子类的构造函数中调用它。

你怎么知道要创建什么类型的实例? 如果您将拥有派生类的现有实例并希望创建与其基本相同的另一个实例,则应该让您的基类型实现受保护的虚拟CloneBase方法,该方法调用MemberwiseClone并执行基类型的任何深度复制。 ,以及一个链接到CloneBase并转换为基类型的公共Clone方法。 每个派生类型都应该重写CloneBase以链接到base.CloneBase并添加任何必要的额外深度复制(如果不需要额外的深层复制逻辑,则可以省略该步骤),并且还将公共Clone方法与链接到CloneBase和将结果转换为其类型[使用单独的CloneBase可以使用不同的签名声明新的Clone方法,同时还可以覆盖并链接到基类方法]。

如果您将拥有新类的现有实例,但希望从其他实例复制其属性,则可以使用抽象的ConstructInstanceLike(x)方法,每个派生类型将实现该方法以调用其构造函数或克隆本身并修改克隆以匹配传入的对象。 这两种方法都不是非常优雅,但两者都可以起作用。

如果您没有新类的现有实例,则需要一些其他方法来获取适当类型的内容。 最好的方法可能是存储Func委托的集合,每个派生类型对应一个感兴趣的派生类型,然后调用其中一个函数来生成相关派生类型之一的对象。 也可以定义一个接口

 IFactory { TResult Create(TParams param); } 

但在许多情况下,代表会更方便使用。