1

I dont' understand the use of the [NonSerialized] attribute when implementing ISerializable on a class. I attended the "programming in C#" (Microsoft 20-483) course and it's used in few examples, but not in details.
Take this 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);
    }
}

I commented what I expect: _Age is a private field that I don't want to serialize. I specifically written in GetObjectData to serialize it. It's a curious thing to do, but I wanted to understand how [NonSerialized] would be handled.
If I run something like this in the 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);
        }
    }
}

The age is there... In the file where the serialized object is and in the rehydrated object. My question is: why? What's the use of the [NonSerialized] attribute in this case since we just have to not add Age in the GetObjectData method? I'm clearly missing something, but I can't figure what. Thanks!

Edit: the example that is present in the course:

[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);
    }
}
benichka
  • 925
  • 1
  • 11
  • 32
  • Is it because you are applying this attribute to a private field, while the serializer are actually serialize the property? It does not prevent the property from being serialized by applying [NonSerialized] on the backing filed. Also please check [this answer](https://stackoverflow.com/questions/4184680/set-the-nonserializedattribute-to-an-auto-property) – kennyzx Aug 13 '17 at 14:09
  • Thanks but the link didn't really help me :( I found an answer on Microsoft WebSite, I think... – benichka Aug 14 '17 at 16:23

1 Answers1

2

OK, so I found something interesting on Microsoft website:
https://learn.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.

So, basically, that's why I didn't understand the use of [NonSerialized] when implementing ISerializable: they're not meant to work together.

benichka
  • 925
  • 1
  • 11
  • 32