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

标签 c# .net json serialization json.net

我想弄清楚如何从我的 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 实际上会包含一个名为 Thang 而不是 Data 的属性,如下所示。

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

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

谢谢。

最佳答案

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

您确实需要使用一点反射,并且您可能会使用自定义 JsonConverter , 但您也可以使用自定义 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

关于c# - Json.NET 在序列化时获取通用属性类型名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26629430/

相关文章:

c# - 如何从对象数据源获取数据集列值

c# - 用于构建加载我的程序集并构建序列化 NHibernate 配置的 MSBuild 任务

c# - 使用两次时中继器错误

c# - 在 C# 代码中提取 7zip

java - 简单的 Java 加密和 JSON 友好的编码?

json - 从 Confluence JSON 响应中获取值(value)

c# - OpenGL 中的纹理显示为单色

c# - 使用 ScriptManager.RegisterClientScriptIninclude 注册 JavaScript 文件

c# - 使用 html Agility Pack 选择属性值

c# - 当数组表示为具有 "item#XXX"属性的对象时读取 JSON