Сериализация в XML - частные свойства - PullRequest
4 голосов
/ 28 августа 2009

Я ищу способ сериализации POCO, который содержит некоторые свойства только для чтения. В некоторых поисках Google и StackOverflow я видел следующие предложения:

  • использовать DataContractSerializer ; или
  • использовать SoapFormatter или BinaryFormatter ; или
  • заменить мои свойства только для чтения на свойства чтения / записи ;

Мои занятия очень просты, они выглядят так:

public class MyClass
{
    public int Id { get; private set; }
    public string Name { get; private set; }
    public MyClass(int id, string name)
    {
        Id = id;
        Name = name;
    }
}

Итак,

  • Я не хочу, чтобы мои свойства читались / записывались. Если они доступны только для чтения, это потому, что моя модель домена запрашивает свойства только для чтения. Модель предметной области не может измениться только из-за этого.
  • Я не хочу использовать DataContractSerializer, так как это приведет к загрязнению моей доменной модели материалами, связанными с сериализацией.
  • BinaryFormatter не очень хороший вариант, так как в результате получается byte[], и я хотел бы трактовать его как string (и я не хочу иметь дело с Encondings и т. П. При десериализации моего объекта ).

Что мне действительно нужно, так это класс XmlSerializer, способный сериализовать свойства только для чтения .

Знаете ли вы о такой реализации? Или любое другое удобное решение?

Спасибо!

Ответы [ 2 ]

4 голосов
/ 28 августа 2009

Ну, обычно XmlSerializer не может сериализовать свойства только для чтения ... однако существует возможность сериализации свойств с внутренним набором: вам нужно сгенерировать сборку сериализации XML и объявить ее «другом». сборка с использованием атрибута InternalsVisibleTo. Вы можете автоматизировать это, добавив следующий код в файл проекта:

  <Target Name="AfterBuild"
          DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource"
          Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)"
          Outputs="$(OutputPath)$(_SGenDllName)">
    <SGen BuildAssemblyName="$(TargetFileName)"
          BuildAssemblyPath="$(OutputPath)"
          References="@(ReferencePath)"
          ShouldGenerateSerializer="true"
          UseProxyTypes="false"
          KeyContainer="$(KeyContainerName)"
          KeyFile="$(KeyOriginatorFile)"
          DelaySign="$(DelaySign)"
          ToolPath="$(SGenToolPath)">
      <Output TaskParameter="SerializationAssembly"
              ItemName="SerializationAssembly" />
    </SGen>
  </Target>

А в AssemblyInfo.cs:

[assembly: InternalsVisibleTo("MyAssembly.XmlSerializers")]

Конечно, вы можете не захотеть, чтобы свойства имели внутренний набор, но если вы это сделаете, решение, приведенное выше, должно работать.

1 голос
/ 06 ноября 2009

Хотя было бы неплохо, если бы serialize мог получить доступ к частным свойствам, к сожалению, на сегодняшний день нет простого способа.

Но есть и другой вариант архитектурного решения. НЕ разрушайте требования к вашему бизнес-домену, вместо этого разделяйте уровни, аналогичные дизайну nTeir, и реализуйте DTO ...

Если вы разделяете свой бизнес, datafacade / dataadaptor (здесь хорошо подходит заводской шаблон) и уровни DataAccess на 3 проекта, которыми вы можете управлять, ссылаясь на то, что бизнес никогда не знает о вашем DTO. Смысл в том, что если вы решили удалить или реализовать сериализацию или поменять ее на сохранение на SQL-сервере, это никак не повлияет на ваш бизнес-уровень.

Всегда есть один недостаток, нужно написать еще кучу кода: * вам нужно написать конвертер объектов в обе стороны для каждой сущности, которую вы хотите перейти в Dataaccess * вы потенциально можете уничтожить некоторые из скрытых объектов OO. Метод BusinessSave в бизнесе должен быть переведен на правильный тип в Dataface, прежде чем перейти к dataaccess

Вы можете сделать это намного проще с помощью чего-то вроде nHybinate или аналогичного. ура Choco

...