Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Xml Serializer deserializes list to count of 0 instead of null

I am confused on how XmlSerializer works behind the scenes. I have a class that deserializes XML into an object. What I am seeing is for the following two elements that are NOT part of the Xml being deserialized.

[XmlRootAttribute("MyClass", Namespace = "", IsNullable = false)]
public class MyClass
{
    private string comments;
    public string Comments
    {
        set { comments = value; }
        get { return comments; }
    }

    private System.Collections.Generic.List<string> tests = null;
    public System.Collections.Generic.List<string> Tests
    {
        get { return tests; }
        set { tests = value; }
    }
}

Let's take the following XML as an example:

<MyClass>
  <SomeNode>value</SomeNode>
</MyClass>

You notice that Tests and Comments are NOT part of the XML.

When this XML gets deserialized Comments is null(which is expected) and Tests is an empty list with a count of 0.

If someone could explain this to me it would be much appreciated. What I would prefer is that if <Tests> is missing from the XML then the list should remain null, but if a (possibly empty) node <Tests /> is present then the list should get allocated.

like image 963
Maxqueue Avatar asked Jul 27 '17 18:07

Maxqueue


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.


2 Answers

What you are observing is that members referring to modifiable collections such as List<T> are automatically pre-allocated by XmlSerializer at the beginning of deserialization. I am not aware of any place where this behavior is documented. It may be related to the behavior described in this answer to XML Deserialization of collection property with code defaults, which explains that, since XmlSerializer supports adding to get-only and pre-allocated collections, if a pre-allocated collection contains default items then the deserialized items will be appended to it - possibly duplicating the contents. Microsoft may simply have chosen to pre-allocate all modifiable collections at the beginning of deserialization as the simplest way of implementing this.

The workaround from that answer, namely to use a surrogate array property, works here as well. Since an array cannot be appended to, XmlSerializer must accumulate all the values and set them back when deserialization is finished. But if the relevant tag is never encountered, XmlSerializer apparently does not begin accumulating values and so does not call the array setter. This seems to prevent the default pre-allocation of collections that you don't want:

[XmlRootAttribute("MyClass", Namespace = "", IsNullable = false)]
public class MyClass
{
    private string comments;
    public string Comments
    {
        set { comments = value; }
        get { return comments; }
    }

    private System.Collections.Generic.List<string> tests = null;

    [XmlIgnore]
    public System.Collections.Generic.List<string> Tests
    {
        get { return tests; }
        set { tests = value; }
    }

    [XmlArray("Tests")]
    public string[] TestsArray
    {
        get
        {
            return (Tests == null ? null : Tests.ToArray());
        }
        set
        {
            if (value == null)
                return;
            (Tests = Tests ?? new List<string>(value.Length)).AddRange(value);
        }
    }
}

Sample .Net fiddle showing that Tests is allocated only when appropriate.

like image 148
dbc Avatar answered Oct 19 '22 13:10

dbc


When you apply [System.Xml.Serialization.XmlElement(IsNullable = true)] to the property, the List will be null after deserialization.

like image 1
Don Kedero Avatar answered Oct 19 '22 12:10

Don Kedero