Ошибка .NET XmlSerializer, когда два класса имеют свойства с одинаковым именем - PullRequest
4 голосов
/ 14 апреля 2011

Готовь свои горящие факелы людям!Кто-то в Интернете предлагает ошибку в .NET Framework!: -)

Рассмотрим эту придуманную модель:

public class Barn
{
    public Horse Horse { get; set; }
    public Motorcycle Motorcycle { get; set; }
}

public class Horse
{
    public Horse()
    {
        Rider = "Jim Craig";
    }

    [XmlElement(IsNullable = true, Namespace = "abc")]
    public string Rider { get; set; }
}

public class Motorcycle
{
    public Motorcycle()
    {
        Rider = "Ghost";
    }

    [XmlElement(IsNullable = false, Namespace = "abc")]
    public string Rider { get; set; }
}

Обратите внимание на два свойства Rider, которые имеют одно и то же имя и пространство имен, но в остальном не связаны.Один из них XML-обнуляемый, другой - нет.

Вот некоторый код для сериализации XML, а затем десериализации нулевого всадника:

// Create a Barn, with a Horse, with a null Rider
Barn barnBefore = new Barn();
barnBefore.Horse = new Horse();
barnBefore.Horse.Rider = null;

// Serialize and then deserialize the Barn
XmlSerializer serializer = new XmlSerializer(typeof(Barn));
MemoryStream stream = new MemoryStream();
serializer.Serialize(stream, barnBefore);
stream.Seek(0, SeekOrigin.Begin);
Barn barnAfter = (Barn)serializer.Deserialize(stream);

// Is the Horse's Rider still null?
Console.WriteLine(barnAfter.Horse.Rider == null ? "null" : "not null");

Свойство Horse * Riderимеет IsNullable = true, поэтому его нулевое значение должно поддерживаться посредством сериализации.Запустив приведенный выше код, вы получите действительно null .Пока все хорошо.

Теперь вот забавная часть: поменяйте местами порядок свойств Horse и Motorcycle в классе Barn, так что Motorcycle будет первым.

Запустите его снова, и теперь вывод будет не нуль .Что за черт?!

Я тестировал на VS 2008 и 2010.

Для большего удовольствия попробуйте сделать два свойства Rider различными типами, например один a string идругой int.Это действительно облажается XmlSerializer.

Меня не интересует, как обойти эту проблему.Это тривиально.У меня вопрос: это ошибка или в чем я не понимаю?

1 Ответ

3 голосов
/ 14 апреля 2011

Ну, в первом случае написанный XML выглядит примерно так:

<Barn>
  <Horse>
    <Rider xsi:nil="true" xmlns="abc" />
  </Horse>
</Barn>

Однако во втором случае XML выглядит так:

<Barn>
  <Horse />
</Barn>

Итак, во втором случае, по существу, то, что происходит во время десериализации, таково:

Barn barn = new Barn();
barn.Hose = new Horse();

И так, потому что мы устанавливаем Rider по умолчанию в конструкторе, он остается "Джим Крейг".

Интересно то, что поведение можно изменить, просто изменив порядок элементов в Barn. Чтобы узнать больше, мы можем покопаться, используя ILSpy и Sgen.exe - просто запустите sgen для нашей сборки и посмотрите на сгенерированную сборку.

Мы обнаружили, что в первом случае сгенерированный код в обоих Write2_Horse и Write3_Motorcycle методах имеет строку, которая выглядит следующим образом:

base.WriteNullableStringLiteral("Rider", "abc", o.Rider);

Однако во втором случае это выглядит так:

base.WriteElementString("Rider", "abc", o.Rider);

Я не вижу никакой причины, почему изменение порядка элементов, подобных этому, должно изменить поведение сериализации обоих элементов Horse и Motorcycle таким образом, так что вкратце это выглядит для меня как ошибка в генераторе сборки сериализации XML.

Вы, вероятно, должны сообщить об этом в Microsoft: -)

...