XmlSerializer сериализует пустой список целых в атрибуте - PullRequest
1 голос
/ 29 мая 2019

Рассмотрим такой элемент:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="XMLSchema1" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Foo">
    <xs:complexType>
      <xs:attribute name="MyList">
        <xs:simpleType>
          <xs:list itemType="xs:int" />
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
</xs:schema>

Например:

<Foo MyList='1 2 3' />

Это соответствует этому классу C #:

[Serializable]
public class Foo
{
  [XmlAttribute]
  public int[] MyList { get; set; }
}

И это (в основном)то, что генерирует xsd.exe /classes.

Сериализация и десериализация прекрасно работает, за исключением десериализации пустого списка:

var ser = new XmlSerializer(typeof(Foo));
ser.Deserialize(new StringReader("<Foo MyList='' />"));

AFAIK, это совершенно допустимый XML, но XmlSerializer выдает InvalidOperationException:

System.InvalidOperationException: There is an error in XML document (1, 6). ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo.Read2_Foo(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo.Read3_Foo()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
   at Blah.Program.Main(String[] args) in Program.cs:line 17

(Это исключение из .NET 4.7.2; .NET Core 2.2 выдает то же исключение с почти идентичной трассировкой стека.) Это исключение имеет смысл, поскольку "" не являетсяцелое число.

Существует этот аналогичный вопрос , но он касается перечислений, и я не знаю, как использовать там ответ для int с.

Какя могу получить десериализацию пустого списка, работающего без реализации IXmlSerializable (что требует много дополнительного кодирования)?

1 Ответ

1 голос
/ 29 мая 2019

Я не уверен, что есть какая-то магия, которую вы можете сделать с атрибутами сериализатора, чтобы заставить это работать, и, поскольку это атрибут, вы не можете добавить сложный тип, чтобы помочь скрыть проблему.Вы можете использовать свойство proxy, которое обрабатывает ввод как строку, чтобы обойти проблему, которая, хотя она и не красива, избавляет от необходимости полной реализации IXmlSerializable.

[Serializable]
public class Foo
{
    [XmlIgnore]
    public int[] MyList { get; set; }

    [XmlAttribute(AttributeName = "MyList")]
    public string MyListProxy
    {
        get
        {
            if (MyList == null) return String.Empty;
            return String.Join(" ", MyList);
        }
        set
        {
            MyList = String.IsNullOrWhiteSpace(value) ? new int[0] : value
                .Split(' ')
                .Select(a => int.Parse(a))
                .ToArray();
        }
    }
}
...