C# 属性的内部setter是否可以序列化?

C# 属性的内部setter是否可以序列化?,c#,.net,serialization,C#,.net,Serialization,有没有办法用C#中的内部setter序列化属性? 我知道这可能有问题,但如果有办法的话,我想知道 示例: [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;

有没有办法用C#中的内部setter序列化属性?
我知道这可能有问题,但如果有办法的话,我想知道

示例:

[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();
<?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>
序列化类Person实例的代码:

[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();
<?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>
结果(缺少ID属性):

[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();
<?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>

帕特里克
27
我认为唯一的替代方法是实现并自己编写/解析对象xml


编辑:阅读评论后,看起来很有趣;)

如果您正在执行“默认”XML序列化,它将只查看公共属性。实现
IXmlSerializable
将让您准确地控制序列化的内容。如果您正在执行“标准”.NET序列化,它将查看字段,而不是属性,因此您的对象仍将正确序列化,而无需实现任何额外的接口。

这不是我在未做一些工作的情况下发现的。我认为这是因为生成的
XmlSerializer
使用反射来生成一个新类(该类位于新程序集中,因此无法查看
内部成员/方法)

使用生成代码,然后出于您的目的将其修改为内部类,可能需要一些时间,因此您可以执行以下操作:

XmlSerializer serializer = new MyPersonXmlSerializer();
另一个选项(可能更好)是实现,它将引导自动生成的代码做正确的事情。

如果是选项,(.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(重新格式化):


27
1.
帕特里克

您可以实现,不幸的是,这否定了XmlSerializer最重要的优点(声明式控制序列化的能力)。(基于xml的)和(基于二进制的)可以作为XmlSerializer的替代品,它们各有优缺点。

这当然是可能的。我想用
XElement
来说明一个解决方案,顺便说一句,我非常喜欢这个解决方案。如果您不希望这样做,则无需使用
XmlSerializer
DataContract序列化器
或任何类或属性批注,如
[DataContract]
[Serializable]
。此外,下面的示例显示了在我的示例中,如何将
私有集
内部集
进行交换,顺便说一下:

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
那样将您的类限制为公共setter。

或使用DataContractSerializer我同意Marc-请先查看DataContractSerializer,因为它会为您省去很多麻烦。我认为“standard”指的是“BinaryFormatter”;在大多数情况下,这不太标准,因为所有框架(CF、Silverlight等)都支持xml序列化,但BinaryFormatter不支持。Xml序列化也更具可移植性;或者还有第三方可移植二进制序列化程序。所谓“标准”,我的意思是基于标准的.NET接口,如IFormatter。没有理由不能使用基于XML的格式化程序。事实上,这就是SoapFormatter。我也是。这太棒了!您的答案是有效的,但
async
不适用,而
IXmlSerializer
允许异步序列化。