Могу ли я сконфигурировать DataContractSerializer, чтобы не создавать необязательные (то есть Nullable <> и List <>) элементы в выходном XML?

Я использую новый .NET 3.0 DataContractSerializer. У меня есть объекты Nullable < > и List < > , которые я собираюсь сериализовать. Пример:

[DataContract(Namespace = "")]
class Test
{
    public static void Go()
    {
        Test test = new Test();

        var dcs = new DataContractSerializer(typeof(Test));
        dcs.WriteObject(new StreamWriter("test.xml").BaseStream, test);
    }

    [DataMember]
    public Nullable<int> NullableNumber = null;

    [DataMember]
    public int Number = 5;

    [DataMember]
    public List<int> Numbers = new List<int>();
}

Когда .NET сериализует нулевой или пустой список, он помещает nil (для Nullable) и пустые (для списков) элементы в XML. Вышеприведенный пример генерирует:

<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <NullableNumber i:nil="true"/>
  <Number>5</Number>
  <Numbers xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</Test>

По причинам у меня нет времени для описания, я хотел бы удалить лишние элементы NullableNumber и Numbers, например:

<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Number>5</Number>
</Test>

В самом деле, этот файл десериализуется с помощью сериализатора просто отлично.

Спасибо за вашу помощь!

Ответы

Ответ 1

Отметьте поле с помощью

   [DataMember(EmitDefaultValue=false)]

Это будет работать, по крайней мере, в случае типа nullable value type. Для случая списка вам может потребоваться отложить создание списка до тех пор, пока он не понадобится, или иначе null, если он пуст до сериализации.

Ответ 2

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

    public override string ToString()
    {
        var doc = XDocument.Parse(this.ToXML());
        WalkElement(doc.Root);
        return doc.ToString( SaveOptions.None );
    }
    void WalkElement(XElement e)
    {
        var n = e.GetNamespaceOfPrefix("i");
        if (n != null)
        {
            var a = e.Attribute(n + "nil");
            if (a != null && a.Value.ToLower() == "true")
                e.Remove();
        }
        foreach (XElement child in e.Elements().ToList())
            WalkElement(child);
    }