Reputation: 489
I have a C# class with a method such as below:
public class MyType
{
public MyType Clone()
{
var clone = (MyType)MemberwiseClone();
// Do some other stuff here with the clone's properties
return clone;
}
}
I have a bunch of other classes where I want to implement the Clone method so I was thinking I could create an abstract base class where I could define the Clone method generically so I don't have to put a concrete implementation in each class.
I would think this is possible but I haven't worked too much with generics and my attempts to do this in the past (months ago, so discarded my code out of frustration) haven't been successful.
Is this possible? If so, how could it be done?
Upvotes: 0
Views: 681
Reputation: 29207
The usefulness of this approach depends significantly on what it is that you're cloning.
Here's a method that I use. The cloning method is a bit crude. It's specifically for objects that are meant to be serialized as JSON.
That's why the generic constraint (TEntity : BaseEntity
) is there. I don't want just anything passed into this method, only something that I know is serializable.
I also avoided using the generic argument for JsonConvert.DeserializeObject
because while I want to cast the result as a specific type, I don't want to pass in an inherited type and get back an instance of a base type.
public static TEntity CloneEntity<TEntity>(this BaseEntity input) where TEntity
: BaseEntity
{
if (input == null) return null;
var serialized = JsonConvert.SerializeObject(input);
return (TEntity)JsonConvert.DeserializeObject(serialized, input.GetType());
}
Although it's already been accepted, I don't recommend adding this to a base class unless absolutely necessary. Before long you might find that you need to clone something that already inherits from a different base class.
This requires the Newtonsoft.JSON package.
As mentioned in a comment, this will do a deep clone. As I stated at the top, this method applies only if serialization/deserialization cloning is appropriate to the types you need to clone. If there were a universally applicable way to clone objects that applied in every case then object
would probably have a public Clone
method.
If we're cloning classes it's likely because they contain data, and where that's the case deep cloning is likely preferable. For example, suppose we have a Customer
class, and one if its properties exposes an Address
object. MemberwiseClone
will clone the value types, but will result in two Customer
objects that share a reference to the same Address
. If we're cloning it's usually because we're trying to create entirely distinct objects. If we think we've cloned something but beneath the surface the original and clone share object references then there's a good chance we'll have bugs.
Upvotes: 2
Reputation: 112279
Built on @Gusman's solution I add the possibility to do some initialization
public abstract class ClonableBase<T>
{
public T Clone()
{
T clone = (T)MemberwiseClone();
Initialize(clone)
return clone;
}
protected virtual void Initialize(T clone)
{
}
}
If the initialization is mandatory, you can also make Initialize
abstract instead.
public class RealClass : ClonableBase<RealClass> {
protected override void Initialize(T clone)
{
// Do some other stuff here with the clone's properties
}
}
Upvotes: 0
Reputation: 15151
Create an abstract generic base and then implement the concrete type on the derived ones:
public abstract class ClonableBase<T>
{
public T Clone()
{
return (T)this.MemberwiseClone();
}
}
public class RealClass : ClonableBase<RealClass> { }
Upvotes: 5