Есть ли способ сериализовать свойство с помощью внутреннего установщика в C#?
Я понимаю, что это может быть проблематично, но если есть способ - я хотел бы знать.
Пример:
[Serializable]
public class Person
{
public int ID { get; internal set; }
public string Name { get; set; }
public int Age { get; set; }
}
Код, сериализующий экземпляр класса Человек:
Person person = new Person();
person.Age = 27;
person.Name = "Patrik";
person.ID = 1;
XmlSerializer serializer = new XmlSerializer(typeof(Person));
TextWriter writer = new StreamWriter(@"c:\test.xml");
serializer.Serialize(writer, person);
writer.Close();
Результат (отсутствует свойство ID):
<?xml version = "1.0" encoding = "utf-8"?>
<Person xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd = "http://www.w3.org/2001/XMLSchema">
<Name>Patrik</Name>
<Age>27</Age>
</Person>





Я думаю, что единственная альтернатива один из способов - реализовать IXmlSerializable и самостоятельно написать / проанализировать объект xml.
Редактировать: После прочтения комментариев DataContractSerializer выглядит интересно;)
Я согласен с Марком - сначала посмотрите DataContractSerializer, так как это избавит вас от многих головных болей.
Если вы выполняете сериализацию XML "по умолчанию", она будет смотреть только на общедоступные свойства. Внедрение IXmlSerializable даст вам контроль над сериализацией. Если вы выполняете «стандартную» сериализацию .NET, он будет смотреть на поля, а не на свойства, поэтому ваш объект по-прежнему будет правильно сериализован без необходимости реализации каких-либо дополнительных интерфейсов.
Под «стандартным», я полагаю, вы имеете в виду «BinaryFormatter»; в большинстве случаев это стандарт меньше, поскольку XML-сериализация поддерживается во всех фреймворках (CF, Silverlight и т. д.), но BinaryFormatter - нет. Сериализация XML также более переносима; или есть также сторонние портативные двоичные сериализаторы.
Под «стандартным» я подразумеваю на основе стандартных интерфейсов .NET, таких как IFormatter. Нет причин, по которым нельзя использовать средство форматирования на основе XML. Действительно, вот что такое SoapFormatter.
Не то чтобы я нашел, не поработав. Я считаю, что это связано с тем, что созданный XmlSerializer использует отражение для создания нового класса (который находится в новой сборке, поэтому не может видеть элемент / методы internal).
Возможно, есть некоторый недостаток в использовании Предварительный компилятор XmlSerialization для генерации кода, а затем для его преобразования во внутренний класс для ваших целей, поэтому вы должны сделать что-то вроде:
XmlSerializer serializer = new MyPersonXmlSerializer();
Другой вариант (и, вероятно, предпочтительнее) - реализовать IXmlSerializable, который будет направлять автоматически сгенерированный код, чтобы он поступал правильно.
Если это опция, DataContractSerializer (.NET 3.0) может сериализовать закрытые свойства:
[DataContract]
public class Person
{
[DataMember]
public int ID { get; internal set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
}
...
static void Main()
{
Person person = new Person();
person.Age = 27;
person.Name = "Patrik";
person.ID = 1;
DataContractSerializer serializer = new DataContractSerializer(typeof(Person));
XmlWriter writer = XmlWriter.Create(@"c:\test.xml");
serializer.WriteObject(writer, person);
writer.Close();
}
С xml (переформатированным):
<?xml version = "1.0" encoding = "utf-8"?>
<Person xmlns:i = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://schemas.datacontract.org/2004/07/">
<Age>27</Age>
<ID>1</ID>
<Name>Patrik</Name>
</Person>
^^ Я тоже. Это круто!
Вы можете реализовать IXmlSerializable, к сожалению, это сводит на нет самое важное преимущество XmlSerializer (возможность декларативно управлять сериализацией). DataContractSerializer (на основе xml) и BinaryFormatter (на основе двоичного кода) могут использоваться в качестве альтернативы XmlSerializer, каждый из которых имеет свои плюсы и минусы.
Конечно, это возможно. Я хочу проиллюстрировать решение с использованием XElement, которое, кстати, мне очень понравилось. Вам не нужно использовать XmlSerializer или DataContractSerializer или любые аннотации классов или свойств, такие как [DataContract] или [Serializable], в этом отношении, если вы не хотите этого делать. Кроме того, в приведенном ниже примере показано, как, кстати, вы можете заменить private set на internal set в моем примере:
using System;
using System.Linq;
using System.Xml.Linq;
namespace SerializationTesting
{
class Person
{
// Notice how this object type uses private setters, something that the traditional XmlSerializer will complain about if you don't use a wrapper class..
public string Name { get; private set; }
public DateTime Birthday { get; private set; }
public long HeightInMillimeters { get; private set; }
public Gender Gendrality { get; private set; }
// Generate a serialized XElement from this Person object.
public XElement ToXElement()
{
return new XElement("person",
new XAttribute("name", Name),
new XAttribute("birthday", Birthday),
new XAttribute("heightInMillimeters", HeightInMillimeters),
new XAttribute("gendrality", (long)Gendrality)
);
}
// Serialize this Person object to an XElement.
public static Person FromXElement(XElement x)
{
return new Person(
(string)x.Attribute("name"),
(DateTime)x.Attribute("birthday"),
(long)x.Attribute("heightInMillimeters"),
(Gender)(long)x.Attribute("gendrality")
);
}
public Person(string name, DateTime birthday, long heightInMillimeters, Gender gender)
{
Name = name;
Birthday = birthday;
HeightInMillimeters = heightInMillimeters;
Gendrality = gender;
}
// You must override this in conjunction with overriding GetHashCode (below) if you want .NET collections (HashSet, List, etc.) to properly compare Person objects.
public override bool Equals(object obj)
{
if (obj.GetType() == typeof(Person))
{
Person objAsPerson = (Person)obj;
return Name == objAsPerson.Name && Birthday == objAsPerson.Birthday && HeightInMillimeters == objAsPerson.HeightInMillimeters && Gendrality == objAsPerson.Gendrality;
}
return false;
}
// You must override this in conjunction with overriding Equals (above) if you want .NET collections (HashSet, List, etc.) to properly compare Person objects.
public override int GetHashCode()
{
return Name.GetHashCode() ^ Birthday.GetHashCode() ^ HeightInMillimeters.GetHashCode() ^ Gendrality.GetHashCode();
}
// This allows us to compare Person objects using the == operator.
public static bool operator ==(Person a, Person b)
{
return a.Equals(b);
}
// This allows us to compate Person objects using the != operator.
public static bool operator !=(Person a, Person b)
{
return !a.Equals(b);
}
}
public enum Gender
{
Male,
Female
}
class Program
{
static void Main(string[] args)
{
// Create first person (note how UTC time saves and loads properly when casting).
Person personOne = new Person("Alexandru", DateTime.UtcNow, 1000, Gender.Male);
// Save the first person to a local file on the hard disk.
personOne.ToXElement().Save("PersonOne.dat");
// Create second person (not using UTC time this time around).
Person personTwo = new Person("Alexandria", DateTime.Now, 900, Gender.Female);
// Save the second person to a local file on the hard disk.
personTwo.ToXElement().Save("PersonTwo.dat");
// Load the first person from a local file on the hard disk.
XDocument personOneDocument = XDocument.Load("PersonOne.dat");
Person personOneLoadedFromDocument = Person.FromXElement(personOneDocument.Elements().First());
// Load the second person from a local file on the hard disk.
XDocument personTwoDocument = XDocument.Load("PersonTwo.dat");
Person personTwoLoadedFromDocument = Person.FromXElement(personTwoDocument.Elements().First());
// Serialize the first person to a string and then load them from that string.
string personOneString = personOne.ToXElement().ToString();
XDocument personOneDocumentFromString = XDocument.Parse(personOneString);
Person personOneLoadedFromDocumentFromString = Person.FromXElement(personOneDocumentFromString.Elements().First());
// Check for equalities between persons (all outputs will be "true").
Console.WriteLine(personOne.Equals(personOneLoadedFromDocument));
Console.WriteLine(personTwo.Equals(personTwoLoadedFromDocument));
Console.WriteLine(personOne == personOneLoadedFromDocument);
Console.WriteLine(personTwo == personTwoLoadedFromDocument);
Console.WriteLine(personOne != personTwo);
Console.WriteLine(personOneLoadedFromDocument != personTwoLoadedFromDocument);
Console.WriteLine(personOne.Equals(personOneLoadedFromDocumentFromString));
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Как и ожидалось, результатом всех проверок равенства в приведенном выше консольном приложении будет true. Это не страдает от неприятностей, таких как необходимость отслеживать кодировки или способ анализа данных, потому что он делает все это за вас, и он не ограничивает ваш класс общедоступными сеттерами, как это делает XmlSerializer.
Ваш ответ действителен, но async не применим, а IXmlSerializer допускает асинхронную сериализацию.
Или используйте DataContractSerializer