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

Ipq*_*arx 9 c# inheritance constructor abstract-class

我的问题如下:

我有一个需要抽象的基类.它有几个派生类,每个派生类都有自己的特殊属性,这些属性包含在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Tim*_* S. 5

你可以通用createNewInstanceStep1。我还修改了Step2be 类型void(我希望它修改当前实例,因此返回值始终是return this;),因为否则它实际上没有意义,我想在这里使用它。如果像这样改变它没有意义,那么我仅使该方法通用的整个方法将不起作用。

现在createNewInstance使用反射来调用return createNewInstanceStep1<this.GetType()>();.

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<T>() 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;
}
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,另一种方法是自引用泛型类型。不过,最好避免这种情况,因为它很令人困惑,而且总体来说不是一个好的设计。

public sealed class SubClass : BaseClass<SubClass>
{
    protected override SubClass createNewInstanceStep2()
    {
        Console.WriteLine("In step 2");
        return this;
    }
}
public abstract class BaseClass<T> where T : BaseClass<T>, 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();
        ...
Run Code Online (Sandbox Code Playgroud)