从类中获取JSON属性名称列表以在查询字符串中使用

26
如果我有一个C#模型类,用于将数据绑定到由序列化的JSON字符串生成的对象,在此基础上,是否有一种方法可以从该类创建查询字符串以进行初始请求?
模型类示例:
public class model
{
   [JsonProperty(PropertyName = "id")]
   public long ID { get; set; }
   [JsonProperty(PropertyName = "some_string")]
   public string SomeString {get; set;} 
}

查询字符串示例:

baseUrl + uri + "&fields=id,some_string" + token

因此,我试图做的重点是从模型对象中收集“id”和“some_string”,以便我可以动态地创建“&fields”参数。谢谢!

5个回答

40

@Leigh Shepperson 的想法是正确的;不过,您可以使用 LINQ 更少的代码来实现。我会创建一个像这样的辅助方法:

using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
...

public static string GetFields(Type modelType)
{
    return string.Join(",",
        modelType.GetProperties()
                 .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName));
}
你可以像这样使用它:
var fields = "&fields=" + GetFields(typeof(model));

编辑

如果你正在使用3.5版本的.NET Framework,因此没有可用于你的泛型GetCustomAttribute<T>方法,你可以使用非泛型GetCustomAttributes()方法来完成相同的操作,只需将其与SelectManyCast<T>一起使用:

    return string.Join(",",
        modelType.GetProperties()
                 .SelectMany(p => p.GetCustomAttributes(typeof(JsonPropertyAttribute))
                                   .Cast<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName)
                 .ToArray());

谢谢Brian,这是一个非常优雅的解决方案。 - CostelloNicho
我在问题中应该表述得更清楚,这次会议后我会更新。我正在使用Unity3D即修改版的.net 3.5,似乎在4.5中给出了通用类型以获取自定义属性。 - CostelloNicho
太好了,谢谢。只需要在最后一个选择语句后添加.toArray()即可。 - CostelloNicho
@CostelloNicho 很好的发现。我漏掉了那个。我用你的修复更新了我的答案。感谢您的接受! - Brian Rogers
1
@RoLYroLLs - 你的编辑不正确;它跳过了没有[JsonProperty(PropertyName = "XXX")]属性的属性,而不是回退到C#属性名称。你真的应该就这种情况提出另一个问题,但我为这种情况添加了另一个答案 - dbc
显示剩余4条评论

8

您可以使用反射来完成此操作。这是一般的想法:

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;

namespace ConsoleApplication8
{
    public class model
    {
        [JsonProperty(PropertyName = "id")]
        public long ID { get; set; }

        [JsonProperty(PropertyName = "some_string")]
        public string SomeString { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var model = new model();

            var result = string.Empty;

            PropertyInfo[] props = typeof(model).GetProperties();
            foreach (PropertyInfo prop in props)
            {
                foreach (object attr in prop.GetCustomAttributes(true))
                {
                    result += (attr as JsonPropertyAttribute).PropertyName;
                }
            }
        }
    }
}

8
在模型仅部分注释了 [JsonProperty(PropertyName = "XXX")] 属性,或已注释 data contract attributes,或具有 ignored 属性的情况下,您可以使用 Json.NET 的 contract resolver 来获取序列化属性名称列表。 首先,请引入以下扩展方法:
public static class JsonExtensions
{
    public static string [] PropertyNames(this IContractResolver resolver, Type type)
    {
        if (resolver == null || type == null)
            throw new ArgumentNullException();
        var contract = resolver.ResolveContract(type) as JsonObjectContract;
        if (contract == null)
            return new string[0];
        return contract.Properties.Where(p => !p.Ignored).Select(p => p.PropertyName).ToArray();
    }
}

然后,做:
// Allocate the relevant contract resolver. 
// Options are CamelCasePropertyNamesContractResolver() or DefaultContractResolver().
IContractResolver resolver = new DefaultContractResolver(); 

// Get properties
var propertyNames = resolver.PropertyNames(typeof(model));
var fields = "&fields=" + String.Join(",", propertyNames);

对于resolver,如果你使用驼峰式命名属性名称(ASP.NET Core Web API 默认使用此方式),则使用CamelCasePropertyNamesContractResolver;否则使用DefaultContractResolver
示例fiddle

谢谢您,我将尝试在 https://dev59.com/KqTja4cB1Zd3GeqPDo4i 上使用这个。 - RoLYroLLs

0
public class CreateContactProperties
{
   [JsonProperty("email")] public string email { get; set; }
   [JsonProperty("firstname")] public string firstname { get; set; }
}

public string GetJsonPropertyFieldName(PropertyInfo t)
{
   var attr = t.GetCustomAttributes(typeof(JsonPropertyAttribute), true).FirstOrDefault() as JsonPropertyAttribute;

   return attr.PropertyName;
}


IList<PropertyInfo> entityprops = new List<PropertyInfo>(typeof(CreateContactProperties).GetProperties());
foreach (var item in entityprops)
{
  properties += $"{GetJsonPropertyFieldName(item)}, ";
}

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

0
一个小变化的@Brian Rogers解决了空异常问题:
IEnumerable<string> props = typeof(T).GetProperties()
                                     .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
                                     .Where(jp => jp != null)
                                     .Select(jp => jp.PropertyName);

string propsList = string.Join(',', props);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接