Как фильтровать / преобразовывать атрибуты объекта для сериализации с помощью Jsonfx?

Я использую JsonFX для сериализации экземпляра в json, и мне нужно игнорировать некоторые атрибуты и предварительно обрабатывать другие. Как я могу это сделать? Док не очень ясно об этом.

Мой класс выглядит примерно так:

public class Primitive{
    public string type;
    public float[] vertices;
    public int[] indices;
    public int[] edgeIndices;
    public Scene scene;

При выводе JSON мне нужно игнорировать scene атрибут (это целая 3D-сцена) и предварительно обработать vertices, indices, edgeIndices используя некоторую схему сжатия.

И, очевидно, мне нужна симметричная операция при получении json.

Но как?

1 ответ

Решение

Ты можешь использовать [JsonIgnore] вместе с JsonResolverStrategy:

public class Scene
{
    public string Name { get; set; } // Or whatever
}

public class Primitive
{
    public string type;
    public float[] vertices;
    public int[] indices;
    public int[] edgeIndices;
    [JsonFx.Json.JsonIgnore]
    public Scene scene;
}

public class TestClass
{
    public static void Test()
    {
        var primitive = new Primitive
        {
            type = "some type",
            vertices = new[] { 1.0f, 2.0f },
            indices = new[] { 1, 2 },
            edgeIndices = new[] { 0, 1 },
            scene = new Scene { Name = "Should Not Be Serialized" }
        };

        var writer = new JsonWriter(new DataWriterSettings(new JsonResolverStrategy()));

        var json = writer.Write(primitive);

        Debug.WriteLine(json);  // Prints {"type":"some type","vertices":[1,2],"indices":[1,2],"edgeIndices":[0,1]}
        Debug.Assert(!json.Contains("Should Not Be Serialized")); // No assert
    }
}

Или вы можете использовать атрибуты контракта данных вместе с DataContractResolverStrategy:

public class Scene
{
    public string Name { get; set; } // Or whatever
}

[DataContract]
public class Primitive
{
    [DataMember]
    public string type;
    [DataMember]
    public float[] vertices;
    [DataMember]
    public int[] indices;
    [DataMember]
    public int[] edgeIndices;
    [IgnoreDataMember]
    public Scene scene;
}

public class TestClass
{
    public static void Test()
    {
        var primitive = new Primitive
        {
            type = "some type",
            vertices = new[] { 1.0f, 2.0f },
            indices = new[] { 1, 2 },
            edgeIndices = new[] { 0, 1 },
            scene = new Scene { Name = "Should Not Be Serialized" }
        };

        var writer = new JsonWriter(new DataWriterSettings(new DataContractResolverStrategy()));

        var json = writer.Write(primitive);

        Debug.WriteLine(json);
        Debug.Assert(!json.Contains("Should Not Be Serialized")); // No assert
    }
}

(Обратите внимание, что DataContractResolverStrategy не работает в.Net 3.5., поэтому вы не можете использовать его, если застряли на этой старой версии.)

Обновить

Одним из способов "преобразования" свойств во время сериализации является использование свойств прокси, например:

public class Primitive
{
    public string type;

    public float[] vertices;

    [JsonFx.Json.JsonIgnore]
    public int[] indices;

    [JsonFx.Json.JsonName("indices")]
    public string compressedIndices
    {
        get
        {
            return indices.Base64Compress();
        }
        set
        {
            indices = CompressionExtensions.Base64DecompressIntArray(value);
        }
    }

    public int[] edgeIndices;

    [JsonFx.Json.JsonIgnore]
    public Scene scene;
}

public static class CompressionExtensions
{
    public static string Base64Compress(this IEnumerable<int> values)
    {
        if (values == null)
            return null;
        using (var stream = new MemoryStream())
        {
            using (var compressor = new DeflateStream(stream, CompressionMode.Compress, true))
            {
                var _buffer = new byte[4];
                foreach (var value in values)
                {
                    _buffer[0] = (byte)value;
                    _buffer[1] = (byte)(value >> 8);
                    _buffer[2] = (byte)(value >> 16);
                    _buffer[3] = (byte)(value >> 24);
                    compressor.Write(_buffer, 0, 4);
                }
            }
            return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
        }
    }

    public static int[] Base64DecompressIntArray(string base64)
    {
        if (base64 == null)
            return null;
        var list = new List<int>();
        var m_buffer = new byte[4];
        using (var stream = new MemoryStream(Convert.FromBase64String(base64)))
        {
            using (var compressor = new DeflateStream(stream, CompressionMode.Decompress))
            {
                while (compressor.Read(m_buffer, 0, 4) == 4)
                {
                    list.Add((int)(m_buffer[0] | m_buffer[1] << 8 | m_buffer[2] << 16 | m_buffer[3] << 24));
                }
            }
        }
        return list.ToArray();
    }
}

Тогда напиши и прочитай вот так:

        var primitive = new Primitive
        {
            type = "some type",
            vertices = new[] { 1.0f, 2.0f },
            indices = Enumerable.Range(0, 10000).Select(i => 0).ToArray(),
            edgeIndices = new[] { 0, 1 },
            scene = new Scene { Name = "Should Not Be Serialized" }
        };

        var writer = new JsonWriter(new DataWriterSettings(new JsonResolverStrategy()));

        var json = writer.Write(primitive);

        var reader = new JsonReader(new DataReaderSettings(new JsonResolverStrategy()));
        var primitiveBack = reader.Read<Primitive>(json);

        Debug.Assert(primitiveBack.indices.SequenceEqual(primitive.indices));
Другие вопросы по тегам