разница между атрибутом DataContract и атрибутом Serializable в .net - PullRequest
14 голосов
/ 28 декабря 2010

Я пытаюсь создать глубокий клон объекта, используя следующий метод.

    public static T DeepClone<T>(this T target)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, target);
            stream.Position = 0;
            return (T)formatter.Deserialize(stream);
        }
    } 

Этот метод требует объект, который сериализуется, то есть объект класса, который имеет атрибут «Сериализуемый» на нем. У меня есть класс, который имеет атрибут «DataContract», но метод не работает с этим атрибутом. Я думаю, что «DataContract» также является типом сериализатора, но может отличаться от «Serializable».

Может ли кто-нибудь дать мне разницу между ними? Также, пожалуйста, дайте мне знать, если возможно создать глубокий клон объекта только с одним атрибутом, который выполняет работу как атрибутов «DataContract» и «Serializable», или, возможно, другим способом создания глубокого клона?

Пожалуйста, помогите!

Ответы [ 3 ]

23 голосов
/ 28 декабря 2010

Serializable требуется для работы BinaryFormatter.

DataContract и атрибут DataMember используются с DataContractSerializer.

Вы можете украсить класс атрибутами для обоих сериализаторов.

6 голосов
/ 28 декабря 2010

DataContract используется в WCF, следовательно, .NET 3.0+. В .net 2.0 или ниже отсутствует DataContract, атрибут DataMember, только Serializable.

Как сказал Одед, если вы хотите использовать BinaryFormatter, вы должны украсить тип с помощью Serializable .

2 голосов
/ 07 ноября 2013

Однажды я сделал некоторую проверку структуры объекта через Reflection, чтобы найти все сборки, необходимые для десериализации, и сериализовать их вместе с начальной загрузкой.

Немного потрудившись, можно создать аналогичный метод для глубокого копирования.По сути, вам нужен рекурсивный метод, который ведет словарь для обнаружения циклических ссылок.Внутри метода вы проверяете все поля примерно так:

private void InspectRecursively(object input,
    Dictionary<object, bool> processedObjects)
{
  if ((input != null) && !processedObjects.ContainsKey(input))
  {
    processedObjects.Add(input, true);

    List<FieldInfo> fields = type.GetFields(BindingFlags.Instance |
        BindingFlags.Public | BindingFlags.NonPublic );
    foreach (FieldInfo field in fields)
    {
      object nextInput = field.GetValue(input);

      if (nextInput is System.Collections.IEnumerable)
      {
        System.Collections.IEnumerator enumerator = (nextInput as
            System.Collections.IEnumerable).GetEnumerator();

        while (enumerator.MoveNext())
        {
          InspectRecursively(enumerator.Current, processedObjects);
        }
      }
      else
      {
        InspectRecursively(nextInput, processedObjects);
      }
    }
  }
}

Чтобы все заработало, вам нужно добавить объект вывода и что-то вроде System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type), чтобы создать самую мелкую копию (даже без копирования ссылок)значение каждого поля.Наконец, вы можете установить для каждого поля что-то вроде field.SetValue(input, output)

Однако эта реализация не поддерживает зарегистрированные обработчики событий, что также поддерживается десериализацией _ un _.Кроме того, каждый объект в иерархии будет нарушен, если конструктор его класса должен что-либо инициализировать, кроме установки всех полей.Последний пункт работает только с сериализацией, если класс имеет соответствующую реализацию, например, метод, помеченный [OnDeserialized], реализует ISerializable, ....

...