Другое дело: вы могли бы использовать отражение. Если вы кешируете это правильно, то он клонирует 1 000 000 объектов за 5,6 секунды (к сожалению, 16,4 секунды с внутренними объектами).
[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;
}
Я измерил это простым способом, используя класс 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;
РЕЗУЛЬТАТ: С внутренним объектом PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory - просто мой тестовый класс, где у меня есть дюжина тестов, включая использование выражений. Вы можете реализовать это в другой форме в расширении или как угодно. Не забывайте о кешировании.
Я еще не тестировал сериализацию, но сомневаюсь в улучшении с миллионом классов. Я попробую что-нибудь быстрое protobuf / newton.
PS: для простоты чтения я использовал здесь только авто-свойства. Я мог бы обновить с FieldInfo, или вы должны легко реализовать это самостоятельно.
Я недавно протестировал сериализатор Protocol Buffers с функцией DeepClone из коробки. Он выигрывает за 4,2 секунды на миллионе простых объектов, но когда дело доходит до внутренних объектов, он выигрывает с результатом 7,4 секунды.
Serializer.DeepClone(personList);
РЕЗЮМЕ: Если у вас нет доступа к классам, это поможет. В противном случае это зависит от количества объектов. Я думаю, что вы могли бы использовать отражение до 10 000 объектов (возможно, немного меньше), но для большего, чем этот, сериализатор Protocol Buffers будет работать лучше.