Как при использовании ISerializable с DataContractSerializer запретить сериализатору выводить информацию о типе?

Чтобы лучше контролировать сериализацию, я преобразовал класс из [DataContract] в [Serializable], реализовав как GetObjectData, так и специальный конструктор десериализации. Когда я делаю это, сгенерированный XML теперь имеет информацию о типе, применяемую ко всем элементам. Мне не нужна эта лишняя информация, и мне интересно, как сообщить сериализатору, чтобы он не выводил ее.

Вот пример кода, в котором используется [DataContract]:

[DataContract(Namespace = "")]
class Test 
{
    public Test() { }
    [DataMember]
    public Nullable<int> NullableNumber = 7;
    [DataMember]
    public int Number = 5;

    public static void Go()
    {
        var test = new Test();
        var dcs = new DataContractSerializer(typeof(Test));
        using (var s = new StreamWriter("test.xml"))
        {
            dcs.WriteObject(s.BaseStream, test);
        }
    }        
}

Это выводит следующий XML (обратите внимание, что нет информации о типе для Nullable Number и Number — это желаемый результат):

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

Если я изменю приведенный выше код следующим образом (добавив [Serializable], : ISerializable и два метода сериализации):

[Serializable]
class Test : ISerializable
{
    public Test() { }
    public Nullable<int> NullableNumber = 7;
    public int Number = 5;

    public static void Go()
    {
        var test = new Test();
        var dcs = new DataContractSerializer(typeof(Test));
        using (var s = new StreamWriter("test.xml"))
        {
            dcs.WriteObject(s.BaseStream, test);
        }
    }        
    public Test(SerializationInfo info, StreamingContext context)
    {
        NullableNumber = info.GetInt32("NullableNumber");
        Number = info.GetInt32("Number");
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("NullableNumber", NullableNumber);
        info.AddValue("Number", Number);
    }
}

Теперь он выдает следующий XML. Обратите внимание на информацию о типе (i:type="x:int"), добавленную к каждому элементу.

<Test xmlns="http://schemas.datacontract.org/2004/07/XMLSerialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema">
  <NullableNumber i:type="x:int" xmlns="">7</NullableNumber>
  <Number i:type="x:int" xmlns="">5</Number>
</Test>

Почему оно это делает? Как мне остановить его от этого?

Спасибо!


person Eric    schedule 02.04.2009    source источник
comment
Спасибо за вопрос, потому что он решил мой вопрос :-) Что касается того, почему - в первом примере была гарантия, что каждая запись является полем, поэтому вы можете получить тип поля, просто взглянув на Test type. Во втором случае вы управляете, поэтому эти записи вообще не должны быть полями, вы можете записывать/считывать только случайные данные.   -  person astrowalker    schedule 21.01.2017
comment
Теперь для этого есть решение, доступное в .NET Framework 4.5. Смотрите мой ответ ниже   -  person Martin    schedule 06.01.2020


Ответы (3)


Вам нужен ISerializable здесь? Чего вам не давал обычный DataContractSerializer? Если вы вернетесь к этому, все должно работать нормально.

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

Итак: есть ли причина для реализации ISerializable в этом случае?

person Marc Gravell    schedule 02.04.2009
comment
Я сократил пример, чтобы упростить вопрос. Мне нужна пользовательская сериализация по причинам, которые я здесь не показываю. - person Eric; 03.04.2009
comment
Из (длинного списка) причин, по которым мне нужна пользовательская сериализация, самой большой является то, что мне нужно условно выводить определенные свойства на основе другой информации. - person Eric; 03.04.2009
comment
Я не понимаю вашего комментария о том, что он «должен» включать эту дополнительную информацию. Действительно, первый вышеприведенный пример XML прекрасно десериализуется с помощью десериализатора [Serializable], поэтому десериализатору не нужна информация об этом типе. - person Eric; 03.04.2009

Если вам нужен полный контроль над сериализацией в xml, вы можете использовать XmlSerializer

public class Test
{
    [XmlIgnore]
    public Nullable<int> NullableNumber = 7;

    [XmlElement("NullableNumber")]
    public int NullableNumberValue
    {
        get { return NullableNumber.Value; }
        set { NullableNumber = value; }
    }

    public bool ShouldSerializeNullableNumberValue()
    {
        return NullableNumber.HasValue;
    }

    [XmlElement]
    public int Number = 5;
}

пример кода сериализации:

static void Main(string[] args)
{
    XmlSerializer serializer = new XmlSerializer(typeof(Test));
    serializer.Serialize(Console.Out, new Test());
}

Результаты:

<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Number>5</Number>
  <NullableNumber>7</NullableNumber>
</Test>
person Dmitry Kolchev    schedule 29.08.2019

Начиная с .Net Framework 4.5 (и .Net Core 1.0) это возможно с помощью класса DataContractJsonSerializerSettings:

DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings
{
    EmitTypeInformation = EmitTypeInformation.Never
};
var dcs = new DataContractSerializer(typeof(Test), settings);

Настройки EmitTypeInformation говорят сериализатору не выводить (раздражающий?) параметр __type во время сериализации.

Доступен ряд других полезных настроек. Вот страница документации для DataContractJsonSerializerSettings.

person Martin    schedule 06.01.2020