Creating an instance of derived class through the base class without hardcoding

后端 未结 4 1823
说谎
说谎 2020-12-31 14:00

My problem is as follows:

I have a base class that needs to be abstract. It has several derived classes, each with their own special properties that are contained in

相关标签:
4条回答
  • 2020-12-31 14:29

    You can make createNewInstanceStep1 a protected void init method that initiates this object, and call it in each subclass's constructor.

    0 讨论(0)
  • 2020-12-31 14:32

    You could make createNewInstanceStep1 generic. I've also modified the Step2 to be type void (I'm expecting it to modify the current instance, so the return would always be return this; anyway), because otherwise it doesn't really make sense the way I'd like to use it here. If it doesn't make sense to change it like this, then my whole approach of only making this method generic won't work.

    And createNewInstance now uses reflection to call the equivalent of 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;
    }
    

    If this won't work, another approach is a self-referential generic type. It's good to avoid this, though, because it's confusing and overall not a good design.

    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();
            ...
    
    0 讨论(0)
  • 2020-12-31 14:51

    What's the problem with letting the derived classes do the instantiation of the new instance?

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-31 14:55

    How are you going to know what type of instance to create? If you'll have an existing instance of the derived class and want to create another instance which is basically identical to it, you should have your base type implement a protected virtual CloneBase method which calls MemberwiseClone and does any deep copying the base type knows about, and a public Clone method which chains to CloneBase and casts to the base type. Each derived types should override CloneBase to chain to base.CloneBase and add any necessary additional deep copying (that step may be omitted if no additional deep-copy logic is required), and also shadow the public Clone method with one that chains to CloneBase and casts the result to its type [using a separate CloneBase makes it possible to both declare a new Clone method with a different signature while also overriding and chaining to the base-class method].

    If you'll have an existing instance of the new class, but want its properties to be copied from some other instance, could have an abstract ConstructInstanceLike(x) method which each derived type would implement to either call one of its constructors, or clone itself and modify the clone to match the passed-in object. Neither approach is terribly elegant, but either can work.

    If you won't have an existing instance of the new class, you'll need some other means of getting something of the appropriate type. The nicest approach is probably to store a collection of Func<TParams, TResult> delegates, one for each derived type of interest, and then invoke one of those functions to generate an object of one of the associated derived type. It would also be possible to define an interface

    IFactory<TParam, TResult> { TResult Create(TParams param); }
    

    but in many cases a delegate will be more convenient to work with.

    0 讨论(0)
提交回复
热议问题