MemberwiseClone can copy an object. However, all reference types inside the object are still references, so you would need to copy them also by hand.
AFAIK MemberwiseClone uses reflection. That is okay for non-AOT platforms. But I am not sure if it will work on AOT platforms (like iOS).
So, If I need something like this, I create a Clone() method for the given type and copy all values by hand:
public class RandomGenerator
{
// ...
public RandomGenerator Clone()
{
RandomGenerator other = new RandomGenerator();
other.value = this.value;
other.speed = this.speed;
// don't forget to do the same with all other members here.
return other;
}
}
alternatively you could write a CopyTo() method
public class RandomGenerator
{
// ...
public void CopyTo(RandomGenerator other)
{
if(other == null)
throw new NullReferenceException();
other.value = this.value;
other.speed = this.speed;
// don't forget to do the same with all other members here.
}
}
or both:
public class RandomGenerator
{
// ...
public RandomGenerator Clone()
{
RandomGenerator other = new RandomGenerator();
this.CopyTo(other);
return other;
}
public void CopyTo(RandomGenerator other)
{
if(other == null)
throw new NullReferenceException();
other.value = this.value;
other.speed = this.speed;
// don't forget to do the same with all other members here.
}
}
then you can simply do it like this:
rndGen_2 = rndGen_1.Clone();
// or
rndGen_1.CopyTo(rndGen_2);
@Hosnkobf So, one question…would you return RandomGenerator like this…
public RandomGenerator CopyTo(RandomGenerator other)
{
if(other == null)
throw new NullReferenceException();
other.value = this.value;
other.speed = this.speed;
// don't forget to do the same with all other members here.
return other;
}
}
Oh sorry, nvm, I see that you use the Clone() method for what I’m looking for.
Cloning objects is generally a tricky thing, even the developers of the .NET Framework have recognized their ICloneable interface was a bad move, as you can read here.
Anyway, since we’re already on it, if you really need it I’d turn things around and let one instance copy from another. From the object’s view it’s a better responsibility, since it is the one that gets the values and sets them on itself. In the end it’s not much of a difference, to me it feels more natural.
Little side note: Never throw NullReferenceExceptions! This is a situation in which an ArgumentNullException should be thrown.
It finally worked for me and it took a lot of work believe it or not, even though it was a simple process, I didn’t expect this to be such a big issue!
I didn’t actually use the null reference exception, but for mine I had a host of nested classes because I’m making an RPG. Now I can FINALLY simply just do newCharacter = characterData.Clone() and I’m done. It’s a huge relief, it’s necessary when you have a battle system and you’re pulling data from a database into unique characters and you want to basically have clones (like 3 slimes on the battle field for example).
Character {
//Has a few objects, this one object called O_Object in particular.
}
O_Object {
//Has two more, including one called O_Lists_Base
O_Lists_Base o_Lists_Base = new O_Lists_Base();
public O_Object Clone() {
O_Object :eyes:bject_Clone = new O_Object();
:eyes:bject_Clone.o_Lists_Base = this.o_Lists_Base.Clone();
return :eyes:bject_Clone;
}
}
O_Lists_Base {
//has maybe one or two more objects here...
public O_Lists_Base Clone() {
O_Lists_Base o_Lists_Base_Clone = new O_Lists_Base();
o_Lists_Base_Clone.someOtherObject = this.someOtherObject.Clone();
return o_Lists_Base;
}
}
This actually worked very well and cleared up the most prevalent bugs in my engine so far! Thanks a bunch. Still surprised C# doesn’t have this feature built in in some sort of simple fashion.
I had to go into each object and make absolutely sure, double and triple checking it that I got it right, that it cloned it and did not use a reference to the object.
@Suddoha Good points! Thanks also for the link. It is a good read.
And of course it should throw an ArgmuentNullException (silly mistake I normally know^^).
@atracat111 good to hear that you managed to do it. But now you should rename all your “Clone()” methods into “GetDeepCopy()” or something similar, because as of the linked forum thread (and the linked article inside) it is not clear if “Clone” means deep copy or shallaw copy.
There is a reason why it doesn’t exist. It’s the fact that it doesn’t make a lot of sense. Some types would implement the copy functionality as shallow copy, some would make a deep copy or something in between. If you follow the discussion in the link I posted, it might help to see what you’re about to run into.
There are better solutions to this problem, just one of them being the seperation behaviour from transferable state. This does not only help when you need to copy an instance’s state, but also opens up completely new ways to handle the data itself in many situations, no matter if it’s networking, (de-) serialization, sending data back and forth between instances, systems and so on.
And that’s the problem, it’s the alarming downside when you use it. You have an extreme additional effort to make things work properly, everytime you add new things that need to be copyable.
This may not apply to you, but every time I see someone requesting some kind of clone functionality, they’re doing something they shouldn’t be doing. Are you sure you absolutely need this, or do you think there’s another way?