Outra coisa: você pode usar a reflexão. Se você armazenar isso em cache corretamente, clonará 1.000.000 de objetos em 5,6 segundos (infelizmente, 16,4 segundos com objetos internos).
[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;
}
Eu a medi de maneira simples, usando a classe 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;
RESULTADO: Com objeto interno PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory é apenas a minha classe de teste, onde tenho dezenas de testes, incluindo o uso de expressão. Você pode implementar isso de outra forma em uma extensão ou qualquer outra coisa. Não se esqueça do cache.
Ainda não testei a serialização, mas duvido de uma melhoria com um milhão de classes. Vou tentar algo rápido protobuf / newton.
PS: para simplificar a leitura, usei apenas propriedades automáticas aqui. Eu poderia atualizar com o FieldInfo ou você deve implementá-lo facilmente.
Recentemente, testei o serializador de buffers de protocolo com a função DeepClone pronta para uso. Ele vence com 4,2 segundos em um milhão de objetos simples, mas quando se trata de objetos internos, vence com o resultado 7,4 segundos.
Serializer.DeepClone(personList);
RESUMO: Se você não tiver acesso às aulas, isso ajudará. Caso contrário, isso depende da contagem dos objetos. Eu acho que você pode usar reflexão de até 10.000 objetos (talvez um pouco menos), mas, para mais do que isso, o serializador de buffers de protocolo terá um desempenho melhor.