成员的自定义运行时序列化

时间:2012-03-07 09:11:44

标签: c# json.net

我想知道是否有人能指出我正确的方向来轻松解决以下问题:

假设我的.NET代码中有一个Player类,如下所示:

public class Player
{
   public int Id { get; set; }
   public string Name { get; set; }
   public long Score { get; set; }
}

我需要将此类序列化为JSON字符串(使用JSON.NET)并在POST到Web服务时使用它。但是,问题在于某些服务的端点明确禁止在JSON字符串中出现某些成员。例如,“post score”端点将允许所有3个成员包含在字符串中,而“register player”端点仅允许Id和Name存在(否则,将错误请求返回给客户端) )。现在我知道我可以创建两个不同的类(例如Player和CompetitivePlayer),每个类都包含所需的(子)成员集,但是出于实际目的,让我们假设我不能这样做或者想要避免这种情况(我的实际数据对象)比这里给出的Player类更复杂,只是作为例子。)

所以我真正想要的是在运行时告诉JSON序列化程序,只有某个对象的某些成员必须在情境X中被序列化,而在情况Y中,整个不同的子集将被序列化。起初我认为实现我自己的ContractResolver会有所帮助,但事实证明,每个对象的类型只调用一次,而不是每个对象本身在序列化时调用。现在,我能想到的唯一解决方案是继承JSONSerializer并让它使用JSONWriter忽略其名称包含在作为参数给出的字符串列表中的属性 - 也许 - 虽然我不太确定这个计划是否可行。对于我想要实现的目标,是否有更简单的解决方案?

2 个答案:

答案 0 :(得分:3)

好的,在查看了JSON.NET源代码之后,我找到了阻止我自定义序列化这些属性的确切位置:CamelCasePropertyNamesContractResolver类。

在编写原始问题之前,我尝试在IContractResolver部分实现此处所述的自定义序列化。但是,我没有直接从DefaultContractResolver继承,而是使用CamelCasePropertyNamesContractResolver(我在这里需要骆驼案例),在查看其代码后,设置了一个"共享缓存"由于性能原因(我愿意在这种情况下牺牲),因此阻止某些方法被调用的标志。因此,CreateProperties()每个对象类型只调用一次,而不是每次我的对象都需要序列化。所以现在我的合同解析器类看起来像这样:

class OptionalPropertiesContractResolver : DefaultContractResolver
{
    //only the properties whose names are included in this list will be serialized
    IEnumerable<string> _includedProperties;

    public OptionalPropertiesContractResolver(IEnumerable<string> includedProperties)
    {
        _includedProperties = includedProperties;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        return (from prop in base.CreateProperties(type, memberSerialization)
                where _includedProperties.Contains(prop.PropertyName)
                select prop).ToList();
    }

    protected override string ResolvePropertyName(string propertyName)
    {
        // lower case the first letter of the passed in name
        return ToCamelCase(propertyName);
    }

    static string ToCamelCase(string s)
    {
        //camel case implementation
    }
}

只是想让别人知道这种特殊情况,以防万一遇到它。

答案 1 :(得分:0)

我会创建合约类并使用AutoMapper从Player类映射到它们并根据需要序列化它们。即'PlayerContract','CompetitivePlayerContract'等。

这些类只代表您服务的合同并不重要。