Сериализация JSON.NET для объекта с членом типа Stream?

Надеюсь, это легкое решение, которое я забыл. У меня есть объект, переданный в обработчик событий, который я хочу сериализовать этот объект с помощью JSON.NET, например:

public void OnEvent(IEventObject foo)
{
    // Serialize foo to string/disk here?
    var data = JsonConvert.SerializeObject(foo, Formatting.Indented);
}

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

Я не знаю, как сериализовать этот объект в любом случае:

  • a) Преобразование потоков в данные и их сериализация
  • b) Игнорирование потоков и сериализация оставшихся членов

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

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

Ответ 1

По умолчанию Json.NET будет пытаться сериализовать свойства потока, что не очень полезно. Вы можете изменить поведение, создав свой собственный контрактный преобразователь. Вот пример, который полностью игнорирует все Stream:

public class IgnoreStreamsResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(
        MemberInfo member,
        MemberSerialization memberSerialization
    )
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (typeof(Stream).IsAssignableFrom(property.PropertyType))
        {
            property.Ignored = true;
        }
        return property;
    }
}

Используйте его как:

var bytes = new byte[] { 1, 2, 3 };
var eo = new EventObject { OtherValue = 2, MyStream = new MemoryStream(bytes) };
var s = JsonConvert.SerializeObject(eo,
  new JsonSerializerSettings { ContractResolver = new IgnoreStreamsResolver() });
// {"OtherValue":2}

Изменив другие свойства JsonProperty, вы можете внести другие изменения. Наиболее подходящим для вас может быть Converter, который позволит вам указать свой собственный класс, чтобы определить, как сериализовать Stream (например, преобразовать его в byte[] и сериализовать его как base64).

Все это делается без каких-либо изменений интерфейса или класса реализации.