Игнорировать свойство во время сериализации с использованием BinaryFormatter, только если его значение null

В настоящее время я использую BinaryFormatter для создания потока. Мне известно, что я могу пометить свойство атрибутом [field: NonSerialized], если я хочу, чтобы BinaryFormatter игнорировал его во время сериализации. Мой вопрос заключается в том, есть ли способ указать, что все нулевые свойства поля должны игнорироваться во время двоичной сериализации? В настоящее время я делаю что-то подобное, чтобы получить поток

       var formatter = new BinaryFormatter();
        using (var stream = new MemoryStream())
        {
            formatter.Serialize(stream, MyObjectinstance);
        }

person MistyD    schedule 10.04.2020    source источник
comment
Ознакомьтесь со статьей Пользовательская сериализация, атрибут OnSerializing тут вроде как вариант   -  person Pavel Anikhouski    schedule 10.04.2020


Ответы (2)


Каков ваш конкретный вариант использования исключения этого из сериализации? Null почти не займет места, и это не улучшит производительность десериализации или сериализации. При десериализации вы также можете обрабатывать null по-другому, обрабатывая событие OnDeserialized.

person Knodel12    schedule 10.04.2020
comment
Дело не в хэше. Я вычисляю хэш из этого потока. Nulls изменит хэш - person MistyD; 11.04.2020

Не предназначен именно для этой цели, но ISerializationSurrogate может помочь.

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

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

public class NullFieldOmittingSurrogate : ISerializationSurrogate
{
    void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        if (obj != null)
        {
            foreach (FieldInfo field in obj.GetType().GetFields
                (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                object fieldValue = field.GetValue(obj);
                if (fieldValue != null)
                {
                    info.AddValue(field.Name, fieldValue);
                }
            }
        }
    }

    object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        // The deserialization works without the need for this surrogate
        throw new NotImplementedException();
    }
}

Нам нужно передать этот суррогат нашему бинарному форматеру, поэтому вот метод, который передает ему эту и другую необходимую информацию:

public static void SerializeObject(object myObjectInstance, Stream destinationStream)
{
    SurrogateSelector surrogateSelector = new SurrogateSelector();
    surrogateSelector.AddSurrogate
    (
        myObjectInstance.GetType(),
        new StreamingContext(StreamingContextStates.All),
        new NullFieldOmittingSurrogate()
    );
    IFormatter serializer = new BinaryFormatter();
    serializer.SurrogateSelector = surrogateSelector;
    serializer.Serialize(destinationStream, myObjectInstance);
}

И, наконец, как использовать: (SerClass не имеет значения и представляет собой класс, имеющий 4 свойства, все типа object, для модульного тестирования)

public static void Main()
{
    MemoryStream memoryStream = new MemoryStream();
    SerializeObject
    (
        new SerClass()
        {
            Prop2 = 5,
            Prop4 = "ABCD",
            Nested = new SerClassNested() { Prop1 = 8, Prop3 = "EFGH" }
        },
        memoryStream
    );

    SerClass serClass = new BinaryFormatter().Deserialize(memoryStream) as SerClass;
}

Надеюсь это поможет. Я все еще работаю над полями типа вложенного класса.

person Oguz Ozgul    schedule 10.04.2020