Un'altra cosa: potresti usare la riflessione. Se lo memorizzi correttamente nella cache, clonerà 1.000.000 di oggetti in 5,6 secondi (purtroppo, 16,4 secondi con oggetti interni).
[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;
}
L'ho misurato in modo semplice, usando la 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;
RISULTATO: Con oggetto interno PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory è solo la mia classe di test in cui ho dozzine di test incluso l'uso dell'espressione. Potresti implementarlo in un'altra forma in un'estensione o altro. Non dimenticare la memorizzazione nella cache.
Non ho ancora testato la serializzazione, ma dubito di un miglioramento con un milione di classi. Proverò qualcosa di veloce protobuf / newton.
PS: per semplicità di lettura, ho usato solo la proprietà automatica qui. Potrei aggiornare con FieldInfo o dovresti implementarlo facilmente da solo.
Di recente ho testato il serializzatore Buffer di protocollo con la funzione DeepClone pronta all'uso. Vince con 4,2 secondi su un milione di oggetti semplici, ma quando si tratta di oggetti interni, vince con il risultato 7,4 secondi.
Serializer.DeepClone(personList);
SOMMARIO: Se non hai accesso alle lezioni, questo ti aiuterà. Altrimenti dipende dal conteggio degli oggetti. Penso che potresti usare la riflessione fino a 10.000 oggetti (forse un po 'meno), ma per di più il serializzatore Protocollo Buffer funzionerà meglio.