一尘不染

Json.NET在序列化时获取通用属性类型名称?

json

我试图弄清楚如何从我的API返回一个核心对象

public class Response<T> {
    public T Data {get;set;}
}

其中T是一些具有属性的对象,例如

public class Thang {
   public string Thing  {get;set;}
}

使用 JsonConvert.Serialize( myResponse );T Data属性返回为Data,正确的是。

但是,如果我想使用名称作为类型T呢?因此,响应Json实际上将包含一个名为Thangnot 的属性Data,如下所示。

{
    "thang": {
        "thing" : "hey"
    }
}

我很好奇是否有一个相对简单的方法可以用Json.net做到这一点,或者您是否必须创建一个自定义JsonConverterT在编写时使用反射来获取类型名称?

谢谢。


阅读 281

收藏
2020-07-27

共1个答案

一尘不染

据我所知,没有内置的方法可以做到这一点。

您确实需要使用一点反射,并且您可能可以使用custom JsonConverter,但是您也可以使用custom
在几行代码中做到这一点ContractResolver

public class GenericPropertyContractResolver :
      CamelCasePropertyNamesContractResolver
{
    private readonly Type genericTypeDefinition;

    public GenericPropertyContractResolver(Type genericTypeDefinition)
    {
        this.genericTypeDefinition = genericTypeDefinition;
    }

    protected override JsonProperty CreateProperty(
        MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty baseProperty =
            base.CreateProperty(member, memberSerialization);

        Type declaringType = member.DeclaringType;

        if (!declaringType.IsGenericType ||
            declaringType.GetGenericTypeDefinition() != this.genericTypeDefinition)
        {
            return baseProperty;
        }

        Type declaringGenericType = declaringType.GetGenericArguments()[0];

        if (IsGenericMember(member))
        {
            baseProperty.PropertyName =
                this.ResolvePropertyName(declaringGenericType.Name);
        }

        return baseProperty;
    }

    // Is there a better way to do this? Determines if the member passed in
    // is a generic member in the open generic type.
    public bool IsGenericMember(MemberInfo member)
    {
        MemberInfo genericMember = 
            this.genericTypeDefinition.GetMember(member.Name)[0];

        if (genericMember != null)
        {
            if (genericMember.MemberType == MemberTypes.Field)
            {
                return ((FieldInfo)genericMember).FieldType.IsGenericParameter;
            }
            else if (genericMember.MemberType == MemberTypes.Property)
            {
                PropertyInfo property = (PropertyInfo)genericMember;

                return property
                    .GetMethod
                    .ReturnParameter
                    .ParameterType
                    .IsGenericParameter;
            }
        }

        return false;
    }
}

然后,您可以像这样使用它:

var settings = new JsonSerializerSettings();
settings.ContractResolver = new GenericPropertyContractResolver(typeof(Response<>));

string serialized = JsonConvert.SerializeObject(new Response<Thang> 
{ 
    Data = new Thang { Thing = "Hey" }
}, settings);

可能更直接的方法是Dictionary在序列化类之前将其转换为。

确定封闭的泛型类型的属性是否对应于开放的泛型类型的泛型属性时,我也遇到了一些麻烦-对此的任何提示将不胜感激。

示例: https
//dotnetfiddle.net/DejOL2

2020-07-27