【问题标题】:Specify output format of DataContractJsonSerializer?指定 DataContractJsonSerializer 的输出格式?
【发布时间】:2017-08-20 01:24:41
【问题描述】:

对于手头的项目,我必须使用DataContractJsonSerializer 进行序列化,并且必须根据成员的值生成特定的输出。

我的班级看起来像这样:

public class MyClass
{
  public string foo;
  public string bar;

  public MyClass(string f, string b = "")
  {
    this.foo = f;
    this.bar = b;
  }
}

现在序列化一个类似的列表

var list = new List<MyClass>
{
  new MyClass("foo", "bar"),
  new MyClass("foo1"),
  new MyClass("foo2", "bar2")
};

应该是这样的

[{"foo": "bar"}, "foo1", {"foo2": "bar2"}]

或者 - 更好的是 - 转义并作为string

"[{\"foo\": \"bar\"}, \"foo1\", {\"foo2\": \"bar2\"}]"
  • 字符串和对象的混合物。我怎么能做到这一点?

我试图覆盖 ToString() 方法并序列化相应的字符串,从而导致不必要的转义符号,例如bar2 可能是 m/s 并被转义为 m\\/s,无法在 Web 服务器上正确反序列化。

最后,我只需要序列化为这种格式。无需使用DataContractJsonSerializer 反序列化此格式。

【问题讨论】:

  • 我相信没有办法纯粹使用DataContractJsonSerializer 来做到这一点,因为它与DataContractSerializer 共享一个代码库,用于序列化data contract types,因此不提供对底层序列化格式的访问( JSON 或 XML)。
  • 如果您切换到json.net,这将很容易做到。或者,您可以调用JsonReaderWriterFactory.CreateJsonWriter() 并按照Mapping Between JSON and XML 中给出的规则手动序列化您自己的JSON 输出。
  • 我只需要序列化成这种格式。

标签: c# json serialization


【解决方案1】:

您想要做的是将MyClass 的实例有条件地替换为serialization surrogate(即string 或字典),但是数据协定序列化不支持使用原语作为代理项,如解释的那样here 来自微软。

但是,由于您只需要序列化而不需要反序列化,因此您可以通过将 List&lt;MyClass&gt; 手动替换为代理 List&lt;object&gt; 来获得所需的输出,其中 MyClass 的实例在 @987654336 时被替换为字符串@ 为空,否则为 Dictionary&lt;string, string&gt;。然后手动construct 一个DataContractJsonSerializerDataContractJsonSerializerSettings 中使用以下值:

(请注意,DataContractJsonSerializerSettingsEmitTypeInformationUseSimpleDictionaryFormat 都是 .NET 4.5 的新手。)

因此,您可以如下定义您的MyType

public interface IHasSerializationSurrogate
{
    object ToSerializationSurrogate();
}

public class MyClass : IHasSerializationSurrogate
{
    public string foo;
    public string bar;

    // If you're not going to mark MyClass with data contract attributes, DataContractJsonSerializer
    // requires a default constructor.  It can be private.
    MyClass() : this("", "") { }

    public MyClass(string f, string b = "")
    {
        this.foo = f;
        this.bar = b;
    }

    public object ToSerializationSurrogate()
    {
        if (string.IsNullOrEmpty(bar))
            return foo;
        return new Dictionary<string, string> { { foo, bar } };
    }
}

然后介绍以下扩展方法:

public static partial class DataContractJsonSerializerHelper
{
    public static string SerializeJsonSurrogateCollection<T>(this IEnumerable<T> collection) where T : IHasSerializationSurrogate
    {
        if (collection == null)
            throw new ArgumentNullException();
        var surrogate = collection.Select(i => i == null ? null : i.ToSerializationSurrogate()).ToList();
        var settings = new DataContractJsonSerializerSettings
        {
            EmitTypeInformation = EmitTypeInformation.Never,
            KnownTypes = surrogate.Where(s => s != null).Select(s => s.GetType()).Distinct().ToList(),
            UseSimpleDictionaryFormat = true,
        };
        return DataContractJsonSerializerHelper.SerializeJson(surrogate, settings);
    }

    public static string SerializeJson<T>(this T obj, DataContractJsonSerializerSettings settings)
    {
        var type = obj == null ? typeof(T) : obj.GetType();
        var serializer = new DataContractJsonSerializer(type, settings);
        return SerializeJson<T>(obj, serializer);
    }

    public static string SerializeJson<T>(this T obj, DataContractJsonSerializer serializer = null)
    {
        serializer = serializer ?? new DataContractJsonSerializer(obj == null ? typeof(T) : obj.GetType());
        using (var memory = new MemoryStream())
        {
            serializer.WriteObject(memory, obj);
            memory.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(memory))
            {
                return reader.ReadToEnd();
            }
        }
    }
}

并手动将您的列表序列化为 JSON,如下所示:

var json = list.SerializeJsonSurrogateCollection();

结果如下:

[{"foo":"bar"},"foo1",null,{"foo2":"bar2"}]

如果您确实需要对字符串进行转义(为什么?),您始终可以将结果字符串第二次序列化为 JSON,并使用DataContractJsonSerializer 生成双序列化结果:

var jsonOfJson = json.SerializeJson();

导致

"[{\"foo\":\"bar\"},\"foo1\",{\"foo2\":\"bar2\"}]"

【讨论】:

  • 我认为这是正确的方向。尽管如此,如果 bar 为空,我需要的输出为"[foo value]",如果不是,则为{"[foo value]" : "[bar value]"}
  • @vonludi - 不敢相信我错过了。答案已更新。
  • 感谢您的帮助。关于“为什么要逃”问题:我认为根据此答案stackoverflow.com/questions/20510437/… 在httpwebrequest 中使用字符串时需要转义字符串
  • 感谢您的帮助。这给了我正确的想法。
【解决方案2】:

将根据名称和值组合进行反序列化,因此您的文本应该是这样的 [{“foo”:“foo”,“bar”:“bar”},{“foo”:“foo1”},{“foo”:“foo2”,“bar”:“bar2”}]

【讨论】:

  • 那么,您是说不可能以任何方式覆盖或实施以获得所需的输出吗?如果存在非空 bar,则为 {[value of foo]: [value of bar]},否则为 [value of foo]。
猜你喜欢
  • 1970-01-01
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 2014-09-24
相关资源
最近更新 更多