2016-12-17 59 views
2

我正在尝试编写一个自定义合约解析器,该解析器在Newtonsoft.Json.Serialization中扩展DefaultContractResolver,目的是将ExpandoObject中的所有属性转换为具有PascalCase属性名称。扩展DefaultContractResolver以将ExpandoObject子属性转换为PascalCase

我的合同:

public class Fruit 
{ 
    public int Id { get; set; } 
    public ExpandoObject FruitProperties { get; set; } 
} 

我传递的以下数据:

{ 
    "Id": "1234", 
    "FruitProperties" : { 
     "colour": "red", 
     "Taste": "sweet 
    } 

    } 

} 

我期待的结果如下:

{ 
    "Id": "1234", 
    "FruitProperties" : { 
     "Colour": "red", 
     "Taste": "sweet" 
    } 
} 

我曾尝试重写ResolvePropertyName ,并且DefaultContractResolver中的CreateProperty方法没有运气。所有这些都跳过expando对象中的子属性。有谁知道我需要重写DefaultContractResolver中的什么方法来将Expando中的子属性名称转换为PascalCase?

回答

1

ExpandoObject没有通过反射序列化,因此修改CreateProperty将不起作用。相反,它被序列化为IDictionary<string, object>。因此,您可以利用Json.NET 9.0.1中新增的NamingStrategy类型来创建自定义命名策略,以仅为PascalCase 字典密钥,而不是别的。 NamingStrategy有一个属性NamingStrategy.ProcessDictionaryKeys,当设置为true,导致Json.NET字典键名称映射:

public class PascalCaseDictionaryKeyNamingStrategy : DefaultNamingStrategy 
{ 
    public PascalCaseDictionaryKeyNamingStrategy() : base() { this.ProcessDictionaryKeys = true; } 

    public override string GetDictionaryKey(string key) 
    { 
     if (ProcessDictionaryKeys && !string.IsNullOrEmpty(key)) 
     { 
      if (char.ToUpperInvariant(key[0]) != key[0]) 
      { 
       var builder = new StringBuilder(key); 
       builder[0] = char.ToUpperInvariant(key[0]); 
       return builder.ToString(); 
      } 
     } 
     return key; 
    } 
} 

然后把它放在DefaultContractResolver.NamingStrategy(或任何custom subclass of DefaultContractResolver如果您喜欢):

var resolver = new DefaultContractResolver { NamingStrategy = new PascalCaseDictionaryKeyNamingStrategy() }; 
var json = JsonConvert.SerializeObject(fruit, Formatting.Indented, new JsonSerializerSettings { ContractResolver = resolver }); 

Console.WriteLine(json); 

输出:

{ 
    "Id": 1234, 
    "FruitProperties": { 
    "Colour": "red", 
    "Taste": "sweet" 
    } 
}