сериализовать атрибуты по умолчанию с помощью XmlSerializer - PullRequest
0 голосов
/ 23 мая 2018

На основе этой публикации я попытался создать дочерний класс XmlTextWriter, который записывает все значения атрибутов, даже значения по умолчанию.Но я не могу заставить это работать.Может кто-нибудь помочь?

Вот класс, который я хочу сериализовать:

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlType(AnonymousType = true)]
[System.Xml.Serialization.XmlRoot(Namespace = "", IsNullable = false)]
public class Foo
{
    public string content { get; set; }

    [System.Xml.Serialization.XmlAttribute()]
    [System.ComponentModel.DefaultValue(true)]
    public bool isActive { get; set; }
}

Вот код, где я создаю экземпляр Foo и сериализую его в строку:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces(
    new XmlQualifiedName[] { new XmlQualifiedName("", "") });
    // I need that for not writing a namespace during serialization
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
Foo f = new Foo();
f.content = "hello";
f.isActive = false;

string fStr;
using (MemoryStream ms = new MemoryStream())
using (XmlWriter wr = new XmlTextWriter(ms, new UTF8Encoding(false)))
{
    serializer.Serialize(wr, f, ns);
    ms.Position = 0;
    using (StreamReader sr = new StreamReader(ms))
    {
        fStr = sr.ReadToEnd();
    }
}

Этот код даст мне следующее содержимое для fStr:

<?xml version="1.0" encoding="utf-8"?><Foo><content>hello</content></Foo>

Но я также хочу получить значение по умолчанию, написанное явно, то есть

<?xml version="1.0" encoding="utf-8"?><Foo isActive="true"><content>hello</content></Foo>

Поэтому я создал дочерний класс XmlTextWriter и заменил new XmlTextWriter(...) сверху на new DefaultValueXmlTextWriter(...).Вот мой DefaultValueXmlTextWriter класс:

public class DefaultValueXmlTextWriter : XmlTextWriter
{

    public DefaultValueXmlTextWriter(Stream s, Encoding e) : base(s, e) { }
    public DefaultValueXmlTextWriter(string s, Encoding e) : base(s, e) { }
    public DefaultValueXmlTextWriter(TextWriter t) : base(t) { }

    public override void WriteAttributes(XmlReader reader, bool defattr)
    {
        base.WriteAttributes(reader, true);
    }
}

mousover для base.WriteAttributes говорит:

При переопределении в производном классе записывает все атрибуты, найденные в текущемposition в XmlReader.

Так что я предполагал, что всегда выбор true для defattr будет иметь смысл, но это ничего не изменит в выводе.Я тоже пробовал false, тоже не работает.

Есть идеи?

1 Ответ

0 голосов
/ 25 мая 2018

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

var foo = new Foo();
foo.content = "hello";
//foo.isActive is left undefined
Console.WriteLine($"foo.isActive is left undefined");
Console.WriteLine($"foo.isActive = {foo.isActive}");
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
string file = "File.xml";
using (StreamWriter sw = new StreamWriter(file))
{
    serializer.Serialize(sw,foo);
}
bool attExists = File.ReadAllText(file).Contains("isActive");
Console.WriteLine($"It is {attExists} that isActive exists in {file}");
using (StreamReader sr = new StreamReader(file))
{
    Foo test = (Foo)serializer.Deserialize(sr); 
    Console.WriteLine(test.isActive);
}

Результаты, в которых 3-я строка кода изменяется и отражается в выходных данных первой строки теста

foo.isActive is left undefined
foo.isActive = False
It is True that isActive exists in File.xml
False

foo.isActive = true;
foo.isActive = True
It is False that isActive exists in File.xml
False

foo.isActive = false;
foo.isActive = False
It is True that isActive exists in File.xml
False

Если вы возвращаете свои результаты в другоеКласс ваши результаты здесь не будут так хороши.Похоже, что все, что делает аннотация, это говорит сериализатору не выводить значение, если это значение по умолчанию.

Лично я бы достиг этого, установив значение по умолчанию в открытом конструкторе и игнорировав аннотацию все вместе.Намерение является более явным, и реинжиниринг Xmlserializer является способом, чрезмерным и может привести к другим непредвиденным последствиям.

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlType(AnonymousType = true)]
[System.Xml.Serialization.XmlRoot(Namespace = "", IsNullable = false)]
public class Foo
{
    public string content { get; set; }
    [System.Xml.Serialization.XmlAttribute()]
    public bool isActive { get; set; }
    public Foo()
    {
        isActive = true;
    }
}

Выполнение одного и того же теста приводит к гораздо более предсказуемым результатам.

foo.isActive is left undefined;
foo.isActive = True
It is True that isActive exists in File.xml
True

foo.isActive = true;
foo.isActive = True
It is True that isActive exists in File.xml
True

foo.isActive = false;
foo.isActive = False
It is True that isActive exists in File.xml
False

Удачи!

...