XSerializer icon indicating copy to clipboard operation
XSerializer copied to clipboard

Inconsistent behavior for non-default constructors

Open bfriesen opened this issue 10 years ago • 0 comments

Various combinations of constructors produce different results.

Example class

This is the class used for examples below.

public class Foo
{
    private readonly int _bar;
    private readonly string _baz;

    // TODO: Add constructor(s) here

    public int Bar { get { return _bar; } }
    public string Baz { get { return _baz; } }
}

And this is the xml document that we'll be using for the examples. We'll be removing the <Bar> and <Baz> tags to highlight differences in behavior.

<Foo>
  <Bar>123</Bar>
  <Baz>abc</Baz>
</Foo>

Single, non-default constructor

public Foo(int bar, string baz)
{
    _bar = bar;
    _baz = baz;
}

If our example class has a single, non-default constructor, deserialization behaves correctly. It successfully handles an xml document that has or doesn't have <Bar> and <Baz> tags in any combination.

Default constructor + non-default constructor

public Foo()
{
}

public Foo(int bar, string baz)
{
    _bar = bar;
    _baz = baz;
}

When deserializing, the default constructor is always chosen, and _bar and _baz are left uninitialized.

Two non-default constructors with equal number of parameters

public Foo(int bar)
{
    _bar = bar;
}

public Foo(string baz)
{
    _baz = baz;
}

Things get a little weird here. If the xml that we deserialize includes both a <Bar> and a <Baz> element, then we get an InvalidOperationException. But, if we only include a <Bar> element, then the constructor that takes an int is called. And if we only include a <Baz> element, then the constructor that takes a string is called. If we included neither <Bar> nor <Baz>, then the constructor that takes an int is called.

Two non-default constructors with unequal number of parameters

public Foo(int bar, string baz)
{
    _bar = bar;
    _baz = baz;
}

public Foo(string baz)
{
    _baz = baz;
}

This situation makes more sense. If neither <Bar> nor <Baz> are provided, then the single-parameter constructor is called. If <Bar> but not <Baz> is provided, then the two-parameter constructor is called. If <Baz> but not <Bar> is provided, then the single-parameter constructor is called. And if both <Bar> and <Baz> are provided, then the two-parameter constructor.

bfriesen avatar Aug 08 '14 20:08 bfriesen