【问题标题】:How can I use a reserved keyword as an identifier in my JSON model class?如何在我的 JSON 模型类中使用保留关键字作为标识符?
【发布时间】:2013-05-18 06:29:06
【问题描述】:

我以前从未使用过 Web API,但我需要一个可以接受/返回 JSON 对象的 Web 服务,并且使用它似乎是一件合理的事情。它看起来很简单(如果不是为了我的目的有点矫枉过正),但我需要处理的数据结构看起来像:

{
    "values":["foo", "bar"],
    "default":"bar"
}

所以我去制作一个模型对象:

class DropDownValues {
    public string[] values { get; set; }
    public string default { get; set; }
}

问题是 default 似乎是一个受保护的关键字。一定有办法解决这个问题,对吧?

【问题讨论】:

  • 可以试试这个public string selected { get; set; }

标签: c# .net asp.net-mvc asp.net-web-api


【解决方案1】:

您可以在 C# 中使用关键字作为标识符,方法是在它们前面加上 @。

【讨论】:

    【解决方案2】:

    我建议走不同的路。尽可能保持 C# 对象模型的标准(我不会使用 @ 符号和 C# keywords 作为属性名称)

    我们可以分离序列化 (JSON) 世界和 C# 对象 - 只需使用 Json.NET 功能。

    最简单的使用方法之一是使用 Attribute 进行装饰:

    [JsonProperty(PropertyName = "default")]
    public string DefaultValue { get; set; }
    

    在这种情况下,我们必须在项目中引用 Newtonsoft.Json。如果一定是 POCO,我们可以引入 CustomResolver 派生自 DefaultContractResolver 并在那里定义这些转换...

    但在这种情况下,关注点分离是一种更纯粹的解决方案,我会说

    编辑:JSON 合同解析器草案 (参见 cmets)

    重要提示:Newtonsoft.Json 是 Web API 的一部分。它不仅是开源的,甚至连 MS 团队都将其作为核心 JSON 序列化器。

    1) Newtonsoft.Json(作为 Web.API 的一部分)已安装在您的解决方案中。所以你不必单独下载(nuget)。它总是在您的packages 文件夹中。因此,使用属性只是添加引用。它就在那里……

    2) 有一个小草稿如何在保留 POCO 的同时进行属性处理。正如我在这里尝试解释的那样:POCO's, behavior and Peristance Igorance,为了保留 POCO(例如,我们确实从在数据层上使用 NHibernate 的分层架构中获利),我们可以用Contract Resolver替换属性。我们的 POCO 库不需要引用任何东西

    我们只需要扩展服务层:

    public class MyResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(
             MemberInfo member,
             MemberSerialization memberSerialization)
        {
    
            var jProperty = base.CreateProperty(member, memberSerialization);
    
            var propertyInfo = member as PropertyInfo;
            if (propertyInfo == null)
            {
                return jProperty;
            }
    
            // just adjust in case if Property name is DefaultValue
            var isDefaultValueProeprty =
                      propertyInfo.Name.Equals("DefaultValue");
    
            if(isDefaultValueProeprty)
            {
                jProperty.PropertyName = "default";
            }
    
            return jProperty;
        }
        ...
    

    通过这种方式,我们向 serailizer 提供了与 [JsonPropertyAttribute] 相同的信息。

    现在,我们只需要使用它。有很多方法(例如全局),但我们只能为控制器做到这一点:

    protected override void Initialize(HttpControllerContext context)
    {
      base.Initialize(context);
    
      var jSettings = context.Configuration.Formatters.JsonFormatter.SerializerSettings;
      jSettings.ContractResolver = MyResolver;
    }
    

    【讨论】:

    • 我确实喜欢这个解决方案,但不幸的是我不能使用 Newtonsoft(至少不是没有经历很多麻烦)。能否详细介绍一下如何使用 CustomResolver?
    【解决方案3】:

    DropDownValues使用骆驼约定:

    class DropDownValues {
        public string[] values { get; set; }
        public string default { get; set; }
    }
    

    您可以使用前缀 @ 来传递,但它仍然不遵循 C# 编码约定。

    既可以避免保留关键字又可以使用 C# 编码约定的更好的解决方案是使用CamelCasePropertyNamesContractResolver

    class DropDownValues {
        public string[] Values { get; set; }
        public string Default { get; set; }
    }
    

    并自定义 JsonFormatter 以避免 C# 和 json 对象之间的约定不匹配,如下所示:

    var jsonFormatter = configuration.Formatters.JsonFormatter;
    jsonFormatter.SerializerSettings = new JsonSerializerSettings()
    {  
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    };
    

    【讨论】:

      猜你喜欢
      • 2020-06-24
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多