2014-12-04 4 views
2

Я точно не знаю, как подойти к этому типу проблем, которые у меня есть.Копирование объекта шаблона для создания нового из него

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]); 
} 

Так я хочу использовать, например, словарь здесь для того, чтобы сохранить некоторые объекты шаблонов шин и позже, чтобы изменить их с новыми. Проблема здесь в том, что когда я назначаю шину из словаря, она по-прежнему остается той же самой шиной, потому что она является ссылочной переменной типа, но в конце концов я хочу, чтобы она была COPY. Может кто-нибудь помочь мне и, может быть, бросить идею, как я могу подойти к этому сценарию? Я должен также упомянуть, что это критически важная часть.

+1

Проверьте глубину клонирования: http://stackoverflow.com/questions/78536/deep-cloning-objects –

+0

Я подумывал сделать что-то подобное, но для моей игры это немного малоинтересно, что будет на маленькой устройство и клонирование могут происходить 4-5 раз в секунду, за которым следуют другие алгоритмы. Я должен указать, что мне нужно также разумное решение производительности. –

+0

@MamaTate: Производительность не является проблемой, когда она копируется несколько раз. –

ответ

3

Учитывая, что производительность является серьезной проблемой в вашем коде, я бы воздержался от использования автоматизированных методов глубокого клонирования. Вместо этого я рекомендую использовать наиболее эффективную технологию клонирования памяти, доступную в C#, Object.MemberWiseClone() (see the MSDN page here). Этот метод в значительной степени представляет собой оболочку API C memcpy(), которая непосредственно копирует ссылочный блок памяти и делает весь этот процесс молниеносно. Единственное предостережение в этом методе состоит в том, что он создает мелкую копию. То есть типы ссылок в вашем объекте будут по-прежнему указывать на один и тот же экземпляр. Чтобы справиться с этим правильно, вам потребуется немного дополнительной работы.

public interface IDeepCloneable<T> 
{ 
    T DeepClone(); 
} 

class Foo : IDeepCloneable<Foo> 
{ 
    Foo DeepClone() 
    { 
     // The simplest usecase 
     return (Foo)this.MemberWiseClone(); 
    } 
} 

class Bar : IDeepCloneable<Bar> 
{ 
    private Foo _foo; 
    private List<Foo> _lists; 
    private List<int> _valueTypedLists; 

    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; 
    } 
} 

Я сделал несколько тестов для сравнения этой техники и метода двоичного сериализатора, предложенного в комментариях выше. Вот результаты:

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: Вы, возможно, заметили, что я использую свой собственный интерфейс вместо System.ICloneable. Это связано с тем, что встроенные даты интерфейса в эпоху .NET 2.0, когда генерические файлы недоступны. У этого также есть серьезная оговорка, поскольку она не заявляет должным образом свое намерение. В принципе, нет способа узнать, что выйдет из метода Clone. Является ли это мелкой копией, глубокой копией, она даже того же типа? Невозможно убедиться. Вот почему я рекомендую реализовать свои собственные интерфейсы IDeepCloneable и IShallowCloneable.