Otra cosa: podrías usar la reflexión. Si almacena esto correctamente, clonará 1,000,000 de objetos en 5.6 segundos (lamentablemente, 16.4 segundos con 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;
}
Lo medí de una manera simple, usando la clase 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: Con objeto interno PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory es solo mi clase de prueba donde tengo una docena de pruebas que incluyen el uso de la expresión. Puede implementar esto de otra forma en una extensión o lo que sea. No te olvides del almacenamiento en caché.
Todavía no probé la serialización, pero dudo de una mejora con un millón de clases. Probaré algo rápido protobuf / newton.
PD: en aras de la simplicidad de lectura, solo utilicé la propiedad automática aquí. Podría actualizar con FieldInfo, o debería implementar esto fácilmente por su cuenta.
Recientemente probé el serializador Protocol Buffers con la función DeepClone lista para usar. Gana con 4.2 segundos en un millón de objetos simples, pero cuando se trata de objetos internos, gana con el resultado 7.4 segundos.
Serializer.DeepClone(personList);
RESUMEN: Si no tienes acceso a las clases, esto te ayudará. De lo contrario, depende del recuento de los objetos. Creo que podría usar la reflexión de hasta 10,000 objetos (quizás un poco menos), pero para más de esto el serializador de Protocol Buffers funcionará mejor.