Kolejna rzecz: możesz użyć odbicia. Jeśli odpowiednio buforujesz, to sklonuje 1 000 000 obiektów w 5,6 sekundy (niestety 16,4 sekundy z obiektami wewnętrznymi).
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
...
Job JobDescription
...
}
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}
private static readonly Type stringType = typeof (string);
public static class CopyFactory
{
static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();
private static readonly MethodInfo CreateCopyReflectionMethod;
static CopyFactory()
{
CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
}
public static T CreateCopyReflection<T>(T source) where T : new()
{
var copyInstance = new T();
var sourceType = typeof(T);
PropertyInfo[] propList;
if (ProperyList.ContainsKey(sourceType))
propList = ProperyList[sourceType];
else
{
propList = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
ProperyList.Add(sourceType, propList);
}
foreach (var prop in propList)
{
var value = prop.GetValue(source, null);
prop.SetValue(copyInstance,
value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
}
return copyInstance;
}
Zmierzyłem to w prosty sposób, używając klasy Watcher.
var person = new Person
{
...
};
for (var i = 0; i < 1000000; i++)
{
personList.Add(person);
}
var watcher = new Stopwatch();
watcher.Start();
var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
watcher.Stop();
var elapsed = watcher.Elapsed;
REZULTAT: Z obiektem wewnętrznym PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory to tylko moja klasa testowa, w której mam kilkanaście testów, w tym użycie wyrażeń. Możesz to zaimplementować w innej formie w rozszerzeniu lub czymkolwiek. Nie zapomnij o buforowaniu.
Nie testowałem jeszcze serializacji, ale wątpię w poprawę z milionem klas. Spróbuję czegoś szybkiego protobuf / newton.
PS: dla uproszczenia czytania użyłem tu tylko właściwości automatycznej. Mógłbym zaktualizować za pomocą FieldInfo, lub powinieneś łatwo to zaimplementować samodzielnie.
Niedawno przetestowałem serializator buforów protokołu z funkcją DeepClone po wyjęciu z pudełka. Wygrywa z 4,2 sekundy na milion prostych obiektów, ale jeśli chodzi o obiekty wewnętrzne, wygrywa z wynikiem 7,4 sekundy.
Serializer.DeepClone(personList);
PODSUMOWANIE: Jeśli nie masz dostępu do zajęć, to pomoże. W przeciwnym razie zależy to od liczby obiektów. Myślę, że możesz użyć odbicia do 10 000 obiektów (może nieco mniej), ale dla więcej niż to serializator Buforów protokołów będzie działał lepiej.