C#:实现 ISerializable 时的 [NonSerialized]

C#: [NonSerialized] when implementing ISerializable

在 class 上实现 ISerializable 时,我不明白 [NonSerialized] 属性的用法。我参加了 "programming in C#" (Microsoft 20-483) 课程,它用在了几个例子中,但没有详细说明。
拿这个 class:

[Serializable]
public class TestNonSerializable : ISerializable
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [NonSerialized]
    private int _Age;
    public int Age
    {
        get { return this._Age; }
        set { this._Age = value; }
    }

    public TestNonSerializable()
    { }

    public TestNonSerializable(SerializationInfo info, StreamingContext context)
    {
        FirstName = info.GetValue("Name", typeof(string)) as string;
        LastName = info.GetValue("LastName", typeof(string)) as string;
        // I expect this to throw an exception because the value doesn't exists.
        // But it exists!
        Age = (int)info.GetValue("Age", typeof(int));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Name", FirstName);
        info.AddValue("LastName", LastName);
        // I expect this to be empty
        info.AddValue("Age", Age);
    }
}

我评论了我的期望:_Age 是我不想序列化的私有字段。我特意写在GetObjectData里面来序列化。这是一件奇怪的事情,但我想了解如何处理 [NonSerialized]
如果我 运行 在 Main 中是这样的:

class Program
{
    static void Main(string[] args)
    {
        var myObject = new TestNonSerializable()
        {
            FirstName = "Foo",
            LastName = "Bar",
            Age = 32,
        };

        // Instanciate a SOAP formatter
        IFormatter soapFormat = new SoapFormatter();

        // Serialize to a file
        using (FileStream buffer = File.Create(@"D:\temp\TestNonSerializable.txt"))
        {
            // In the file generated, I expect the age to be empty. But the value
            // is set to 32
            soapFormat.Serialize(buffer, myObject);
        }

        // Deserialize from a file
        using (FileStream buffer = File.OpenRead(@"D:\temp\TestNonSerializable.txt"))
        {
            // The age is being deserialized
            var hydratedObject = soapFormat.Deserialize(buffer);
        }
    }
}

年龄在那里...在序列化对象所在的文件和再水化对象中。我的问题是:为什么? [NonSerialized]有什么用 在这种情况下属性,因为我们只需要不在 GetObjectData 方法中添加 Age? 我显然遗漏了什么,但我不知道是什么。 谢谢!

编辑:课程中的示例:

[Serializable]
public class ServiceConfiguration : ISerializable
{
    [NonSerialized]
    private Guid _internalId;
    public string ConfigName { get; set; }
    public string DatabaseHostName { get; set; }
    public string ApplicationDataPath { get; set; }
    public ServiceConfiguration()
    {
    }
    public ServiceConfiguration(SerializationInfo info, StreamingContext ctxt)
    {
        this.ConfigName
           = info.GetValue("ConfigName", typeof(string)).ToString();
        this.DatabaseHostName
           = info.GetValue("DatabaseHostName", typeof(string)).ToString();
        this.ApplicationDataPath
           = info.GetValue("ApplicationDataPath", typeof(string)).ToString();
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("ConfigName", this.ConfigName);
        info.AddValue("DatabaseHostName", this.DatabaseHostName);
        info.AddValue("ApplicationDataPath", this.ApplicationDataPath);
    }
}

好的,所以我在 Microsoft 网站上发现了一些有趣的东西:
https://docs.microsoft.com/en-us/dotnet/api/system.nonserializedattribute?view=netframework-4.7

The target objects for the NonSerializedAttribute attribute are public and private fields of a serializable class. By default, classes are not serializable unless they are marked with SerializableAttribute. During the serialization process all the public and private fields of a class are serialized by default. Fields marked with NonSerializedAttribute are excluded during serialization. If you are using the XmlSerializer class to serialize an object, use the XmlIgnoreAttribute class to get the same functionality. Alternatively, implement the ISerializable interface to explicitly control the serialization process. Note that classes that implement ISerializable must still be marked with SerializableAttribute.

所以,基本上,这就是为什么我在实施 ISerializable 时不理解 [NonSerialized] 的用法:它们不能一起工作。