A site devoted to discussing techniques that promote quality and ethical practices in software development.

Showing posts with label XmlSerialization. Show all posts
Showing posts with label XmlSerialization. Show all posts

Tuesday, May 21, 2013

XmlSerialization - why two runtime behaviour for class with read-only properties?

Following on from the previous blog post, and just to recap, there are at least two ways to write a class with read only property.

The old way is:

    [ Serializable ]
    public class PersonReadOnly {
        String m_Name;
        Int32 m_Age;
        public String Name {
            get{ return m_Name; }
        }
        public Int32 Age { 
            get{ return m_Age; }
        }

        public PersonReadOnly() {
        }

        public PersonReadOnly (String name, Int32 age) {
            this.m_Name = name;
            this.m_Age = age;
        }
    }

and the other way is to use private setter like this:

    [ Serializable ]
    public class PersonReadOnly1 {
        String m_Name;
        Int32 m_Age;

        public String Name {
            get{ return m_Name; }
            private set { m_Name = value; }
        }
        public Int32 Age { 
            get{ return m_Age; }
            private set { m_Age = value; }
        }

        public PersonReadOnly1() {
        }

        public PersonReadOnly1 (String name, Int32 age) {
            this.Name = name;
            this.Age = age;
        }
    }


These two classes functionally are the same. However, the XmlSerializer exhibits very different behaviour depending on how you write the class. This to me seem rather odd.

In the case of PersonReadOnly, there is no runtime exception, except that the state of the class, namely Name and Age, are not serialized as in agreement with the specification. So when the stream is deserialized, the values of Name and Age are that of the null and 0, respectively. Fair enough!

But when one writes the class as in the style promoted in PersonReadOnly1, the runtime behaviour is radically different. XmlSerializer throws the following InvalidOperationException, which is caused by the exception in sgen.exe,
System.InvalidOperationException: Unable to generate a temporary class (result=1).
error CS0200: Property or indexer 'TestSerialization.PersonReadOnly1.Name' cannot be assigned to -- it is read only
error CS0200: Property or indexer 'TestSerialization.PersonReadOnly1.Age' cannot be assigned to -- it is read only

   at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
   at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
   at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type)
   at TestSerialization.TestXmlSerialization.SerializeClassWithNonPublicSetter_PersonReadOnly1() in E:\Projects\SerializationDemo2\TestSerialization\TestXmlSerialization.cs:line 74


The question is: should CLR exhibit the same runtime behaviour regardless of how the class is constructed?

Saturday, May 11, 2013

XmlSerializer - Difference in runtime behaviour between MS .Net and Mono runtime

There are several ways to define a class in C# with read-only properties.

You could define it like this:
    [ Serializable ]
    public class PersonReadOnly
    {
        String m_Name;
        Int32 m_Age;
        public String Name {
            get{ return m_Name; }
        }
        public Int32 Age { 
            get{ return m_Age; }
        }

        public PersonReadOnly()
        {
        }

        public PersonReadOnly (String name, Int32 age)
        {
            this.m_Name = name;
            this.m_Age = age;
        }
    }

This is the good old way of doing it. When this class is serialized using Xml Serialization, the values of the properties are not serialized.

Alternately, you can declare one with a private setter or using the auto-generated property syntax with private setter, like this:
    [ Serializable ]
    public class WithAutoPropertyReadOnly
    {
        public String Name { get; private set; }
        public Int32 Age { get; private set; }

        public WithAutoPropertyReadOnly() { }

        public WithAutoPropertyReadOnly( string name, Int32 age )
        {
            this.Name = name;
            this.Age = age;
        }
    }

The end result of this class WithAutoPropertyReadOnly is to produce private setters for properties Name and Age.

While WithAutoPropertiesReadOnly and PersonReadOnly classes are functionally the same, the runtime treatments in CLR (MS .Net) and Mono runtime are very different.

CLR and Mono differences
The Mono runtime used in this experiment is version 2.10.8.1 hosted in Ubuntu 12.04 LTS).

When one tries to construct an XmlSerializer object for the class WithAutoPropertiesReadOnly class, like this:
       XmlSerializer ser = new XmlSerializer( typeof(WithAutoPropertiesReadOnly) ); 

CLR runtime throws an exception of type InvalidOperationException while Mono blissfully serializes and deserializes with XmlSerializer in defiant of the specification.

This is dangerous as it introduces runtime differences that can affect cross-platform compatibility. Irrespective if the above piece of code is run in CLR or Mono, the same runtime behaviour should result.

This anomaly between CLR (runtime 2.0 & 4.0) and Mono only manifested by the presence of non-public property setter. In fact, the exception thrown in CLR is due to the runtime exception thrown by sgen.exe when the runtime tries to generate the temporary serialization DLL.

There is no disagreement when trying to serialize the class PersonReadOnly; both CLR and Mono yield the same result that the values for the properties are not serialized in Xml Serialization.






Blog Archive