如何使用反射在C#中获取Json属性名称

4

我有一个如下所示的类:

public class Employee {

    [JsonProperty("emp_id")]
    public int Id {get; set;}

    [JsonProperty("emp_fname")]
    public string Name {get;set;}

    [JsonProperty("emp_lname")]
    public string LastName {get;set;} 
}

在上述类中,我已经分配了 Newtonsoft 属性进行序列化。
我有一个 Employee 类的对象,现在我想通过 JsonProperty 找到属性并获取该属性的值。
例如,我想获取 JsonProprty 属性名称设置为 emp_lname 的属性的值。
是否有一种使用反射来实现这样的取值方式?

我认为JsonProperty标签用于将字符串反序列化。在你的代码里,如果你已经进行了Json反序列化,你可以使用Name而不是emp_fname来访问它的值。 - Jawad
1
var pInfo = [EmployeeInstance].GetType().GetProperties().FirstOrDefault(p => p.GetCustomAttributes<JsonPropertyAttribute>().Any(at => at.PropertyName.Equals("emp_lname"))); - Jimi
1个回答

6
你可以使用Json.NET自带的合同解析器来实现此目的。这样做将正确处理具有和不具有[JsonProperty(string name)]属性的属性,以及直接应用命名策略数据契约属性的对象。
首先添加以下方法:
public static partial class JsonExtensions
{
    static readonly IContractResolver defaultResolver = JsonSerializer.CreateDefault().ContractResolver;

    public static object GetJsonProperty<T>(T obj, string jsonName, bool exact = false, IContractResolver resolver = null)
    {
        if (obj == null)
            throw new ArgumentNullException(nameof(obj));
        resolver = resolver ?? defaultResolver;
        var contract = resolver.ResolveContract(obj.GetType()) as JsonObjectContract;
        if (contract == null)
            throw new ArgumentException(string.Format("{0} is not serialized as a JSON object", obj));
        var property = contract.Properties.GetProperty(jsonName, exact ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
        if (property == null)
            throw new ArgumentException(string.Format("Property {0} was not found.", jsonName));
        return property.ValueProvider.GetValue(obj); // Maybe check JsonProperty.Readable first, and throw an exception if not?
    }
}

现在你可以这样做:

var employee = new Employee
{
    LastName = "last name",
};

Console.WriteLine("Value of {0} is {1}.", "emp_lname", 
                  JsonExtensions.GetJsonProperty(employee, "emp_lname")); // Prints Value of emp_lname is last name.

如果您的应用程序默认使用驼峰式命名法进行JSON序列化,您可以像这样将CamelCasePropertyNamesContractResolver传递给resolver

Console.WriteLine("Value of {0} is {1}.", "emp_lname", 
                  JsonExtensions.GetJsonProperty(employee, "emp_lname", resolver : new CamelCasePropertyNamesContractResolver())); 

如果您需要获取给定类型的所有JSON属性名称列表,请参见从类中获取JSON属性名称列表以在查询字符串中使用。该链接提供了相关信息。
public static partial class JsonExtensions
{
    public static string [] PropertyNames(Type type)
    {
        return PropertyNames(defaultResolver, type);
    }

    //Taken from this answer https://dev59.com/g1wX5IYBdhLWcg3wnwcy#45829514
    //To https://dev59.com/g1wX5IYBdhLWcg3wnwcy
    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();
    }
}

演示 fiddle 在这里


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