5

I have my abstract base class A:

public abstract class A : ICloneable {
 public int Min { get; protected set; }
 public int Max { get; protected set; }
 public A(int low, int high)
 {
 this.Min = low;
 this.Max = high;
 }
 //...
 public object Clone()
 {
 return new this(this.Min, this.Max); //<-- ??
 }
}

Which is extended by my class B:

public class B : A
{
 public B(int low, int high) : base(low, high) { }
 //...
}

Since A is abstract, it cannot be instantiated, but the derived class can. Is it possible to, from class A, create a new instance of class B?

Suppose class A has many derived classes, how will it know which one to instantiate?

Well, I want to instantiate the same class (or type) my currently A is.

That is, if I'm calling the Clone method from a class B, I want to instantiate a new B. If I'm calling the Clone method from a class C, I want to instantiate a new C.

My approach was to write something like:

return new this(this.Min, this.Max);

But that doesn't seem to work nor compile.

Is it possible to accomplish this in C#?

If it isn't, is there an explanation so I can understand?

asked Aug 6, 2014 at 14:47
4
  • This does not answer your question, but why are you not using this.MemberwiseClone() instead ? Commented Aug 6, 2014 at 14:50
  • I was not aware of a MemberwiseClone() method, but I just want the copy to be a new instance, with the same constructor arguments. Any other processing MemberwiseClone may do would be useless Commented Aug 6, 2014 at 14:54
  • What if B construtor adds one more parameter? Commented Aug 6, 2014 at 14:57
  • I hope that doesn't happen Commented Aug 6, 2014 at 15:05

3 Answers 3

8

Yes, this is possible with an abstract factory method on your base class

public abstract class A
{
 public int Min { get; protected set; }
 public int Max { get; protected set; }
 public A(int low, int high)
 {
 this.Min = low;
 this.Max = high;
 }
 protected abstract A CreateInstance(int low, int high);
 public object Clone()
 {
 return this.CreateInstance(this.Min,this.Max);
 }
}
public class B:A
{
 public B(int low, int high)
 : base(low,high)
 {
 }
 protected override A CreateInstance(int low, int high)
 {
 return new B(low,high); 
 }
}
answered Aug 6, 2014 at 14:53
Sign up to request clarification or add additional context in comments.

3 Comments

This solution crossed my mind too, but I was looking forward to not adding construction code in each derived class, but let C# do it for me, instantiating whatever derived class is being used to extend A. I hope I'm explaining myself well enough
@MatiCicero - that's doable but you're going to be dabbling in a lot of reflection. Consider if this is the right solution for you
I'll test both answers and come back with a conclusion. Thank you
5

While I like Jamiec solution, I'm missing dirty solution using reflection :)

public class A {
 public object Clone() {
 var type = GetType().GetConstructor(new[] { typeof(int), typeof(int) });
 return type.Invoke(new object[] { this.Min, this.Max });
 }
}
answered Aug 6, 2014 at 14:58

2 Comments

+1 for the obvious reflection solution that works with non-parameterless ctors
Ohhhh dirty, I like it :D
3

This can be done and your current approach is a well defined design pattern, though most implementations make the Clone an abstract virtual method and override it in all subclasses.

public abstract class A
{
 public abstract A Clone( );
}
public class B : A
{
 public override A Clone( )
 {
 return new B( );
 }
}
public class C : A
{
 public override A Clone( )
 {
 return new C( );
 }
}

Since you are using C# you could make use of the Activator class. You can make the Clone method virtual (not === abstract) with a default implementation of.

public abstract class A
{
 public virtual A Clone( )
 {
 // assuming your derived class contain a default constructor.
 return (A)Activator.CreateInstance(this.GetType( ));
 }
}

Edit - If you do not have a default parameter-less constructor in all of your derived classes, you can add parameters to the Activator.CreateInstance method

(A)Activator.CreateInstance(this.GetType( ), this.Min, this.Max);

For varying constructors on the derived types I would recommend you override the Clone method specifically for those types instead of using the default implementation of Clone.

answered Aug 6, 2014 at 14:55

4 Comments

That last example will have to cast the response to A as in return (A)Activator.CreateInstance(this.GetType( )); as Activator.CreateInstance returns object
This is exactly what I wanted, I will test it and come back with news
The problem with this solution is it relies on a parameterless constructor, which the OP does not have. For reflection solution that works with your constructor look at the other answer @MatiCicero
There is nothing stopping you from adding parameters to the Activator.CreateInstance method. I chose to omit them because derived class constructors are unknown within the scope of A (see edit for continuation..)

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.