Reputation: 283
I don't exactly know how to approach this type of problem that i have.
private Dictionary<int, Tire> m_vehicleTireSelected = new Dictionary<int, Tire>()
{
{0, new TireCasual()
{
Name = "Monster Tire",
Position = new Vector3(-0.94f, -1.09f)
}},
{1, new TireMonster()
{
Name = "Casual Tire",
Position = new Vector3(1.05f, -1.09f)
}}
};
public void ChangeTire(int tireIndex, int tireKey)
{
m_bus.ChangeTire(tireIndex, m_vehicleTireSelected[tireKey]);
}
So i want to use for instance Dictionary here in order to store some tire template objects and later on to change them with new ones. The problem here is when i assign the tire from the dictionary it's still the same tire because it is a reference type variable, but eventually i want it a COPY. Can somebody help me out and maybe throw an idea how i can approach this scenario? I should also mention that this is performance critical part.
Upvotes: 2
Views: 1060
Reputation: 3255
Considering that performance is a major issue in your code, I would refrain from using automated deep cloning techniques. Instead, I recommend using the most efficient memory cloning technique available in C#, Object.MemberwiseClone()
(see the MSDN page here). This method is pretty much a wrapper around the C memcpy()
API which directly copies the referenced block of memory and makes this whole process lightning fast. The only caveat of this technique is that it creates a shallow copy. That is, references types in your object will still points to the same instance. To handle this properly, you need a little bit of extra work.
public interface IDeepCloneable<T>
{
T DeepClone();
}
class Foo : IDeepCloneable<Foo>
{
public Foo DeepClone()
{
// The simplest usecase
return (Foo)this.MemberwiseClone();
}
}
class Bar : IDeepCloneable<Bar>
{
private Foo _foo;
private List<Foo> _lists;
private List<int> _valueTypedLists;
public Bar DeepClone()
{
var clone = (Bar)this.MemberwiseClone();
// This makes sure that deeper references are also cloned.
clone._foo = _foo.DeepClone();
// Though you still need to manually clone types that you do not own like
// lists but you can also turn this into an extension method if you want.
clone._lists = _lists.Select(f => f.DeepClone()).ToList();
// And you can simply call the ToList/ToArray method for lists/arrays
// of value type entities.
clone._valueTypedLists = _valueTypedLists.ToList();
return clone;
}
}
I did some benchmarks to compare this technique and the binary serializer technique proposed in the comments above. Here are the results:
1 000 000 objects composed of 4 ints
Binary Serializer : 10.361799 seconds.
MemberwiseClone : 0.080879 seconds. (128x gain)
1 000 000 objects composed of 4 Lists<int> with 4 items (16 ints + 4 List)
Binary Serializer : 47.288164 seconds.
MemberwiseClone : 0.517383 seconds. (91x gain)
PS: You might have noticed that I use my own interface instead of System.ICloneable. That is because the built-in interface dates of the .NET 2.0 era when generics where not available. It also have a major caveat as it does not properly state its intent. Basically, there is no way to know what will come out of the Clone method. Is it a shallow copy, a deep copy, is it even of the same type? There is no way to make sure. This is why I recommend implementing your own IDeepCloneable and IShallowCloneable interfaces.
Upvotes: 3