Eine andere Sache: Sie könnten Reflexion gebrauchen. Wenn Sie dies richtig zwischenspeichern, werden 1.000.000 Objekte in 5,6 Sekunden geklont (leider 16,4 Sekunden bei inneren Objekten).
[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;
}
Ich habe es auf einfache Weise mit der Watcher-Klasse gemessen.
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;
ERGEBNIS: Mit dem inneren Objekt PersonInstance - 16.4 ist PersonInstance = null - 5.6
CopyFactory ist nur meine Testklasse, in der ich Dutzende von Tests einschließlich der Verwendung von Ausdruck habe. Sie können dies in einer anderen Form in einer Erweiterung oder was auch immer implementieren. Vergessen Sie nicht das Caching.
Ich habe die Serialisierung noch nicht getestet, bezweifle aber eine Verbesserung mit einer Million Klassen. Ich werde etwas schnelles Protobuf / Newton versuchen.
PS: Der Einfachheit halber habe ich hier nur Auto-Property verwendet. Ich könnte mit FieldInfo aktualisieren, oder Sie sollten dies einfach selbst implementieren.
Ich habe kürzlich den Serializer für Protokollpuffer mit der sofort einsatzbereiten DeepClone-Funktion getestet . Es gewinnt mit 4,2 Sekunden auf einer Million einfacher Objekte, aber wenn es um innere Objekte geht, gewinnt es mit dem Ergebnis 7,4 Sekunden.
Serializer.DeepClone(personList);
ZUSAMMENFASSUNG: Wenn Sie keinen Zugriff auf die Klassen haben, hilft dies. Ansonsten kommt es auf die Anzahl der Objekte an. Ich denke, Sie könnten Reflexion von bis zu 10.000 Objekten verwenden (vielleicht etwas weniger), aber für mehr als dies wird der Serializer für Protokollpuffer eine bessere Leistung erzielen.