Я хочу настоящую глубокую копию. В Java это было легко, но как это сделать на C #?
Как сделать глубокую копию объекта в .NET?
- Что делает глубокая копия? Копирует ли он битовый поток? 24.09.2008
- Глубокая копия - это то, что копирует КАЖДОЕ поле объекта. Неглубокая копия создаст только новый объект и укажет все поля на оригинал. 24.09.2008
- Платформа для копирования / клонирования объектов .NET: github.com/havard/copyable 18.02.2011
- Глубокая копия создает второй экземпляр объекта с теми же значениями. Неглубокая копия (упрощенная) подобна созданию второй ссылки на объект. 30.03.2011
- Используйте Mapper, я предлагаю UltraMapper github.com/maurosampietro/UltraMapper 23.04.2017
- проверьте это сообщение: stackoverflow.com/a/52490699/1404642 25.09.2018
- BinaryFormatter небезопасен, посмотрите официальные документы: docs.microsoft.com/en-us/dotnet/api/ 26.01.2021
- Если перфоманс не является проблемой, newtonsoft приходит на помощь ... JsonConvert.DeserializeObject ‹MyType› (JsonConvert.SerializeObject (MyInstance)); 09.06.2021
Ответы:
Важная заметка
BinaryFormatter устарел и больше не будет доступен в .NET после ноября 2023 года. См. Стратегия отмены BinaryFormatter
Я видел несколько разных подходов к этому, но я использую общий служебный метод как таковой:
public static T DeepClone<T>(this T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
Примечания:
Ваш класс ДОЛЖЕН быть отмечен как
[Serializable]
, чтобы это работало.Ваш исходный файл должен включать следующий код:
using System.Runtime.Serialization.Formatters.Binary; using System.IO;
Я написал метод расширения глубокого копирования объектов, основанный на рекурсивном "MemberwiseClone". Это быстро (в три раза быстрее, чем BinaryFormatter), и работает с любыми объектами. Вам не нужен конструктор по умолчанию или сериализуемые атрибуты.
Исходный код:
using System.Collections.Generic;
using System.Reflection;
using System.ArrayExtensions;
namespace System
{
public static class ObjectExtensions
{
private static readonly MethodInfo CloneMethod = typeof(Object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
public static bool IsPrimitive(this Type type)
{
if (type == typeof(String)) return true;
return (type.IsValueType & type.IsPrimitive);
}
public static Object Copy(this Object originalObject)
{
return InternalCopy(originalObject, new Dictionary<Object, Object>(new ReferenceEqualityComparer()));
}
private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
{
if (originalObject == null) return null;
var typeToReflect = originalObject.GetType();
if (IsPrimitive(typeToReflect)) return originalObject;
if (visited.ContainsKey(originalObject)) return visited[originalObject];
if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
var cloneObject = CloneMethod.Invoke(originalObject, null);
if (typeToReflect.IsArray)
{
var arrayType = typeToReflect.GetElementType();
if (IsPrimitive(arrayType) == false)
{
Array clonedArray = (Array)cloneObject;
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));
}
}
visited.Add(originalObject, cloneObject);
CopyFields(originalObject, visited, cloneObject, typeToReflect);
RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect);
return cloneObject;
}
private static void RecursiveCopyBaseTypePrivateFields(object originalObject, IDictionary<object, object> visited, object cloneObject, Type typeToReflect)
{
if (typeToReflect.BaseType != null)
{
RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect.BaseType);
CopyFields(originalObject, visited, cloneObject, typeToReflect.BaseType, BindingFlags.Instance | BindingFlags.NonPublic, info => info.IsPrivate);
}
}
private static void CopyFields(object originalObject, IDictionary<object, object> visited, object cloneObject, Type typeToReflect, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy, Func<FieldInfo, bool> filter = null)
{
foreach (FieldInfo fieldInfo in typeToReflect.GetFields(bindingFlags))
{
if (filter != null && filter(fieldInfo) == false) continue;
if (IsPrimitive(fieldInfo.FieldType)) continue;
var originalFieldValue = fieldInfo.GetValue(originalObject);
var clonedFieldValue = InternalCopy(originalFieldValue, visited);
fieldInfo.SetValue(cloneObject, clonedFieldValue);
}
}
public static T Copy<T>(this T original)
{
return (T)Copy((Object)original);
}
}
public class ReferenceEqualityComparer : EqualityComparer<Object>
{
public override bool Equals(object x, object y)
{
return ReferenceEquals(x, y);
}
public override int GetHashCode(object obj)
{
if (obj == null) return 0;
return obj.GetHashCode();
}
}
namespace ArrayExtensions
{
public static class ArrayExtensions
{
public static void ForEach(this Array array, Action<Array, int[]> action)
{
if (array.LongLength == 0) return;
ArrayTraverse walker = new ArrayTraverse(array);
do action(array, walker.Position);
while (walker.Step());
}
}
internal class ArrayTraverse
{
public int[] Position;
private int[] maxLengths;
public ArrayTraverse(Array array)
{
maxLengths = new int[array.Rank];
for (int i = 0; i < array.Rank; ++i)
{
maxLengths[i] = array.GetLength(i) - 1;
}
Position = new int[array.Rank];
}
public bool Step()
{
for (int i = 0; i < Position.Length; ++i)
{
if (Position[i] < maxLengths[i])
{
Position[i]++;
for (int j = 0; j < i; j++)
{
Position[j] = 0;
}
return true;
}
}
return false;
}
}
}
}
ReferenceEqualityComparer.GetHashCode(object obj)
вы должны использовать RuntimeHelpers.GetHashCode(obj)
, иначе он будет использовать реальный хэш-код объекта. См. stackoverflow.com/a/11240110/495262 23.04.2014 IsPrimitive
: по какой причине вы возвращаете истину для строки. Кроме того, есть ли причина, по которой вы используете сингл &
вместо &&
в заявлении: return (type.IsValueType & type.IsPrimitive);
? 23.04.2014 Delegates
. Вы знаете, работают ли другие подходы и с делегатами? Я бы предположил, что нет. 23.04.2014 Memberwiseclone()
работает так быстро, потому что не вызывает конструкторов. Так что, если ваши конструкторы делают тяжелую работу, такую как подписка на события, вам не повезло. Он полагается на копирование частных полей объекта, минуя бизнес-логику в свойствах и методах. Например, я видел, как поле hashCode
копируется в коллекцию HashSet
, хотя все экземпляры изменились. 26.05.2015 StackOverflowException
при клонировании объектов, которые взаимно ссылаются друг на друга ... Кто-нибудь знает обходной путь? 27.05.2015 .Copy()
работал нормально, если я установил точку останова и проверил содержимое списка в часах перед возобновлением выполнения. Странный. Я обнаружил, что звонки .ToList()
на самом деле достигают того, чего я хочу сейчас, так что все в порядке. Спасибо за ответ :) 27.05.2015 PropertyInfo
. Есть ли способ пометить свойства этого типа как исключенные или разрешенные для ссылки? 13.07.2017 List<BsonElement> { BsonElement ("status=Connected"), BsonElement("lastConnectedTimeUtc=2019-05-15T10:50:40.5570932Z") }
получается: BsonElement[] { BsonElement ("status=Connected"), BsonElement("lastConnectedTimeUtc=2019-05-15T10:50:40.5570932Z"), BsonElement("="), BsonElement("=") }
15.05.2019 if (typeToReflect == typeof(LocalDate) || typeToReflect == typeof(OffsetDateTime)) return originalObject;
10.03.2021 interface IDeepCopy { object DeepCopy(IDictionary<object, object> visited); }
Каждый разработчик делает object DeepCopy(visited) { ..check-visited-add-to-visited..; MyType clone = MemberwiseClone; ... }
, где ... рекурсивно повторяется по мере необходимости. Например. clone.myField1 = myField1.DeepCopy(visited);
или для полей, отличных от IDeepCopy
, выполните вызов InternalCopy
, указанный в ответе. 12.03.2021 Type
объект в качестве члена, Type
сам объект также будет скопирован. И новый кажется таким же, как старый, но сравнение типов между двумя Type
будет неудачным, потому что Type.Equals(Type)
использует сравнение ссылок. И еще одно: если объект 'A' имеет определяемый пользователем struct
член 'B', а 'B' снова имеет ссылку на объект 'C' в качестве члена, объект 'C' не будет глубоко скопирован с ' А '. Пожалуйста, используйте этот код осторожно. 07.05.2021 Основываясь на решении Килхоффера ...
В C # 3.0 вы можете создать метод расширения следующим образом:
public static class ExtensionMethods
{
// Deep clone
public static T DeepClone<T>(this T a)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, a);
stream.Position = 0;
return (T) formatter.Deserialize(stream);
}
}
}
который расширяет любой класс, помеченный как [Serializable], с помощью метода DeepClone
MyClass copy = obj.DeepClone();
this
.. Мощь методов расширения :) 17.04.2013 Вы можете использовать Nested MemberwiseClone для глубокой копии. Его скорость почти такая же, как при копировании структуры значения, и на порядок быстрее, чем (а) отражение или (б) сериализация (как описано в других ответах на этой странице).
Обратите внимание, что если вы используете Nested MemberwiseClone для глубокой копии, вам необходимо вручную реализовать ShallowCopy для каждого вложенного уровня в классе и DeepCopy, который вызывает все указанные методы ShallowCopy. для создания полного клона. Это просто: всего несколько строк, см. Демонстрационный код ниже.
Вот результат кода, показывающий относительную разницу в производительности (4,77 секунды для глубоко вложенного MemberwiseCopy против 39,93 секунды для сериализации). Использование вложенного MemberwiseCopy почти так же быстро, как копирование структуры, а копирование структуры чертовски близко к теоретической максимальной скорости, на которую способен .NET, что, вероятно, довольно близко к скорости того же самого в C или C ++ (но было бы необходимо выполнить некоторые эквивалентные тесты, чтобы проверить это утверждение).
Demo of shallow and deep copy, using classes and MemberwiseClone:
Create Bob
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Clone Bob >> BobsSon
Adjust BobsSon details
BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Elapsed time: 00:00:04.7795670,30000000
Demo of shallow and deep copy, using structs and value copying:
Create Bob
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Clone Bob >> BobsSon
Adjust BobsSon details:
BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Elapsed time: 00:00:01.0875454,30000000
Demo of deep copy, using class and serialize/deserialize:
Elapsed time: 00:00:39.9339425,30000000
Чтобы понять, как сделать глубокую копию с помощью MemberwiseCopy, вот демонстрационный проект:
// Nested MemberwiseClone example.
// Added to demo how to deep copy a reference class.
[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
public class Person
{
public Person(int age, string description)
{
this.Age = age;
this.Purchase.Description = description;
}
[Serializable] // Not required if using MemberwiseClone
public class PurchaseType
{
public string Description;
public PurchaseType ShallowCopy()
{
return (PurchaseType)this.MemberwiseClone();
}
}
public PurchaseType Purchase = new PurchaseType();
public int Age;
// Add this if using nested MemberwiseClone.
// This is a class, which is a reference type, so cloning is more difficult.
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
// Add this if using nested MemberwiseClone.
// This is a class, which is a reference type, so cloning is more difficult.
public Person DeepCopy()
{
// Clone the root ...
Person other = (Person) this.MemberwiseClone();
// ... then clone the nested class.
other.Purchase = this.Purchase.ShallowCopy();
return other;
}
}
// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
public struct PersonStruct
{
public PersonStruct(int age, string description)
{
this.Age = age;
this.Purchase.Description = description;
}
public struct PurchaseType
{
public string Description;
}
public PurchaseType Purchase;
public int Age;
// This is a struct, which is a value type, so everything is a clone by default.
public PersonStruct ShallowCopy()
{
return (PersonStruct)this;
}
// This is a struct, which is a value type, so everything is a clone by default.
public PersonStruct DeepCopy()
{
return (PersonStruct)this;
}
}
// Added only for a speed comparison.
public class MyDeepCopy
{
public static T DeepCopy<T>(T obj)
{
object result = null;
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
result = (T)formatter.Deserialize(ms);
ms.Close();
}
return (T)result;
}
}
Затем вызовите демонстрацию из основного:
void MyMain(string[] args)
{
{
Console.Write("Demo of shallow and deep copy, using classes and MemberwiseCopy:\n");
var Bob = new Person(30, "Lamborghini");
Console.Write(" Create Bob\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Console.Write(" Clone Bob >> BobsSon\n");
var BobsSon = Bob.DeepCopy();
Console.Write(" Adjust BobsSon details\n");
BobsSon.Age = 2;
BobsSon.Purchase.Description = "Toy car";
Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Debug.Assert(Bob.Age == 30);
Debug.Assert(Bob.Purchase.Description == "Lamborghini");
var sw = new Stopwatch();
sw.Start();
int total = 0;
for (int i = 0; i < 100000; i++)
{
var n = Bob.DeepCopy();
total += n.Age;
}
Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total);
}
{
Console.Write("Demo of shallow and deep copy, using structs:\n");
var Bob = new PersonStruct(30, "Lamborghini");
Console.Write(" Create Bob\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Console.Write(" Clone Bob >> BobsSon\n");
var BobsSon = Bob.DeepCopy();
Console.Write(" Adjust BobsSon details:\n");
BobsSon.Age = 2;
BobsSon.Purchase.Description = "Toy car";
Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Debug.Assert(Bob.Age == 30);
Debug.Assert(Bob.Purchase.Description == "Lamborghini");
var sw = new Stopwatch();
sw.Start();
int total = 0;
for (int i = 0; i < 100000; i++)
{
var n = Bob.DeepCopy();
total += n.Age;
}
Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total);
}
{
Console.Write("Demo of deep copy, using class and serialize/deserialize:\n");
int total = 0;
var sw = new Stopwatch();
sw.Start();
var Bob = new Person(30, "Lamborghini");
for (int i = 0; i < 100000; i++)
{
var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
total += BobsSon.Age;
}
Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total);
}
Console.ReadKey();
}
Опять же, обратите внимание, что если вы используете Nested MemberwiseClone для глубокой копии, вам необходимо вручную реализовать ShallowCopy для каждого вложенного уровня в классе и DeepCopy, который вызывает все сказанное ShallowCopy для создания полного клона. Это просто: всего несколько строк, см. Демонстрационный код выше.
Обратите внимание, что когда дело доходит до клонирования объекта, существует большая разница между «структурой» и «классом»:
- Если у вас есть «структура», это тип значения, поэтому вы можете просто скопировать ее, и содержимое будет клонировано.
- Если у вас есть «класс», это ссылочный тип, поэтому, если вы его копируете, все, что вы делаете, - это копируете указатель на него. Чтобы создать настоящий клон, вы должны проявить больше творчества и использовать метод, который создает в памяти еще одну копию исходного объекта.
- Неправильное клонирование объектов может привести к очень сложным для обнаружения ошибкам. В производственном коде я обычно использую контрольную сумму, чтобы дважды проверить, что объект был клонирован правильно и не был поврежден другой ссылкой на него. Эта контрольная сумма может быть отключена в режиме Release.
- Я считаю этот метод весьма полезным: часто вам нужно клонировать только части объекта, а не целиком. Это также важно для любого варианта использования, когда вы изменяете объекты, а затем загружаете измененные копии в очередь.
Обновить
Вероятно, можно использовать отражение, чтобы рекурсивно пройти по графу объекта, чтобы сделать глубокую копию. WCF использует этот метод для сериализации объекта, включая всех его дочерних элементов. Уловка состоит в том, чтобы аннотировать все дочерние объекты с помощью атрибута, который делает их обнаруживаемыми. Однако вы можете потерять некоторые преимущества в производительности.
Обновить
Цитата из независимого теста скорости (см. Комментарии ниже):
Я провел свой собственный тест скорости, используя метод расширения сериализации / десериализации Нила, Nested MemberwiseClone Contango, метод расширения на основе отражения Алекса Бурцева и AutoMapper, по 1 миллиону раз каждый. Сериализация-десериализация была самой медленной, занимая 15,7 секунды. Затем появился AutoMapper, занимавший 10,1 секунды. Намного быстрее оказался метод, основанный на отражении, который занял 2,4 секунды. Безусловно, самым быстрым был Nested MemberwiseClone, занимавший 0,1 секунды. Все сводится к производительности, а не к необходимости добавления кода в каждый класс для его клонирования. Если производительность не является проблемой, используйте метод Алекса Бурцева. - Саймон Тевси
this.Purchase.ShallowCopy()
. Это не имеет смысла, если самой Purchase требуется DeepCopy. Правильный шаблон для истинного DeepCopy - вызывать DeepCopy для каждого непримитивного поля. Любой тип, содержащий только примитивы, просто реализует DeepCopy как ShallowCopy (Person)this.MemberwiseClone()
. В DeepCopy родительский не знает, является ли каждый непримитивный дочерний элемент глубоким или мелким, поэтому он должен вызвать DeepCopy для дочернего элемента. Ответственность ребенка - продолжать глубоко или делать мелкие. Чтобы избежать ошибок, лучше всегда вызывать DeepCopy. Пусть ребенок сам отвечает за себя. 12.03.2021 Я считаю, что подход BinaryFormatter относительно медленный (что стало для меня неожиданностью!). Вы можете использовать ProtoBuf .NET для некоторых объектов, если они соответствуют требованиям ProtoBuf. Со страницы «Приступая к работе с ProtoBuf» (http://code.google.com/p/protobuf-net/wiki/GettingStarted):
Примечания к поддерживаемым типам:
Пользовательские классы, которые:
- Помечены как данные-контракт
- Имейте конструктор без параметров
- Для Silverlight: общедоступны
- Многие общие примитивы и т. Д.
- Одномерные массивы измерений: T []
- Список ‹T> / IList ‹T>
- Словарь ‹TKey, TValue> / IDictionary‹ TKey, TValue>
- любой тип, который реализует IEnumerable ‹T> и имеет метод Add (T)
Код предполагает, что типы будут изменяться вокруг выбранных членов. Соответственно, пользовательские структуры не поддерживаются, поскольку они должны быть неизменяемыми.
Если ваш класс соответствует этим требованиям, вы можете попробовать:
public static void deepCopy<T>(ref T object2Copy, ref T objectCopy)
{
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, object2Copy);
stream.Position = 0;
objectCopy = Serializer.Deserialize<T>(stream);
}
}
Что действительно ОЧЕНЬ быстро ...
Изменить:
Вот рабочий код для модификации этого (протестирован на .NET 4.6). Он использует System.Xml.Serialization и System.IO. Нет необходимости отмечать классы как сериализуемые.
public void DeepCopy<T>(ref T object2Copy, ref T objectCopy)
{
using (var stream = new MemoryStream())
{
var serializer = new XS.XmlSerializer(typeof(T));
serializer.Serialize(stream, object2Copy);
stream.Position = 0;
objectCopy = (T)serializer.Deserialize(stream);
}
}
Вы можете попробовать это
public static object DeepCopy(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DeepCopy(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, DeepCopy(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
Спасибо DetoX83 статье о проекте кода.
Лучший способ:
public interface IDeepClonable<T> where T : class
{
T DeepClone();
}
public class MyObj : IDeepClonable<MyObj>
{
public MyObj Clone()
{
var myObj = new MyObj();
myObj._field1 = _field1;//value type
myObj._field2 = _field2;//value type
myObj._field3 = _field3;//value type
if (_child != null)
{
myObj._child = _child.DeepClone(); //reference type .DeepClone() that does the same
}
int len = _array.Length;
myObj._array = new MyObj[len]; // array / collection
for (int i = 0; i < len; i++)
{
myObj._array[i] = _array[i];
}
return myObj;
}
private bool _field1;
public bool Field1
{
get { return _field1; }
set { _field1 = value; }
}
private int _field2;
public int Property2
{
get { return _field2; }
set { _field2 = value; }
}
private string _field3;
public string Property3
{
get { return _field3; }
set { _field3 = value; }
}
private MyObj _child;
private MyObj Child
{
get { return _child; }
set { _child = value; }
}
private MyObj[] _array = new MyObj[4];
}
Может быть, вам нужна только неглубокая копия, в этом случае используйте Object.MemberWiseClone()
.
В документации на MemberWiseClone()
есть хорошие рекомендации по стратегиям для глубокого копирования: -
http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
public static object CopyObject(object input)
{
if (input != null)
{
object result = Activator.CreateInstance(input.GetType());
foreach (FieldInfo field in input.GetType().GetFields(Consts.AppConsts.FullBindingList))
{
if (field.FieldType.GetInterface("IList", false) == null)
{
field.SetValue(result, field.GetValue(input));
}
else
{
IList listObject = (IList)field.GetValue(result);
if (listObject != null)
{
foreach (object item in ((IList)field.GetValue(input)))
{
listObject.Add(CopyObject(item));
}
}
}
}
return result;
}
else
{
return null;
}
}
Этот способ в несколько раз быстрее, чем BinarySerialization
, И для этого не требуется атрибут [Serializable]
.
Consts.AppConsts.FullBindingList
? 24.04.2018 Документация MSDN, похоже, намекает, что Clone должен выполнять глубокую копию, но это никогда явно не указывается:
Интерфейс ICloneable содержит один член, Clone, который предназначен для поддержки клонирования сверх того, что предоставляется MemberWiseClone ... Метод MemberwiseClone создает неглубокую копию ...
Вы можете найти мой пост полезным.
http://pragmaticcoding.com/index.php/cloning-objects-in-c/
[Serializable]
. поэтому[Serializable]public class Foo { }
сделаетFoo
помеченным как сериализуемый. 04.08.2011if (!typeof(T).IsSerializable) { throw new ArgumentException("Type {0} is not serializable",typeof(T).Name); }
16.07.2013ms.Position = 0
спас мне день! Без этого происходили действительно странные вещи. 06.02.2017