c# - 我可以创建一个仅包含对象类型的空值的 JSON 示例吗?

标签 c# json reflection json.net

我们正在使用 webhook 和事件做一些事情。我想创建一个基于发送到 webhook 的事件类型的 JSON 负载示例。

假设我有这样一个类:

public class TestClass{
    public int Id {get;set;}
}

现在我想要的是能够创建类似的东西

{
    "id": 0
}

仅通过了解 typeof(TestClass)

我不想创建我的对象的实例,因为其中一些相当复杂并且有各种参数要求。

我只想要一个不包含任何值的 JSON 表示。

有什么想法吗?

最佳答案

您可以使用 Json.NET 的 contract resolver类获得JsonContract对于您希望序列化的类型。协定定义 Json.NET 如何序列化类型,因此可用于生成默认表示。

原型(prototype)实现可能如下所示:

public static partial class JsonExtensions
{
    readonly static IContractResolver defaultResolver = new JsonSerializer().ContractResolver;

    public static string WriteDefaultValuesForTypeToString(Type type, IContractResolver resolver = null, Formatting formatting = Formatting.None)
    { 
        using (var sw = new StringWriter())
        {
            using (var jsonWriter = new JsonTextWriter(sw) { Formatting = formatting })
            {
                WriteDefaultValuesForType(type, jsonWriter, resolver);
            }
            return sw.ToString();
        }
    }

    public static void WriteDefaultValuesForType(Type type, JsonWriter writer, IContractResolver resolver = null)
    { 
        var serializer = JsonSerializer.Create(new JsonSerializerSettings{ ContractResolver = resolver });
        WriteDefaultValuesForType(type, writer, serializer, null, 0);
    }

    static void WriteDefaultValuesForType(Type type, JsonWriter writer, JsonSerializer serializer, JsonProperty parent, int depth)
    { 
        var contract = serializer.ContractResolver.ResolveContract(type);
        var defaultValue = parent?.DefaultValue;
        if (defaultValue == null && type.IsValueType && Nullable.GetUnderlyingType(type) == null)
        {
            defaultValue = contract.DefaultCreator();
        }

        if (contract is JsonPrimitiveContract primitive)
        {
            serializer.Serialize(writer, defaultValue);
        }
        else if (contract is JsonObjectContract obj)
        {
            if (depth > 0 && defaultValue == null)
            {
                writer.WriteNull();
            }
            else
            {
                writer.WriteStartObject();

                foreach (var p in obj.Properties)
                {
                    writer.WritePropertyName(p.PropertyName);
                    WriteDefaultValuesForType(p.PropertyType, writer, serializer, p, depth++);
                }

                writer.WriteEndObject();
            }
        }
        else if (contract is JsonArrayContract array)
        {
            writer.WriteStartArray();
            writer.WriteEndArray();
        }
        else if (contract is JsonDictionaryContract dict)
        {
            if (depth > 0 && defaultValue == null)
            {
                writer.WriteNull();
            }
            else
            {
                writer.WriteStartObject();
                writer.WriteEndObject();
            }
        }
        else if (contract is Newtonsoft.Json.Serialization.JsonLinqContract linq)
        {
            /* What to do here? */
            writer.WriteNull();
        }
        else
        {
            //JsonISerializableContract, JsonDynamicContract, 
            throw new JsonSerializationException(string.Format("Unsupported contract {0}", contract));
        }
    }
}

然后,您可以为 TestClass 生成一个默认的 JSON,如下所示:

var defaultJson = JsonExtensions.WriteDefaultValuesForTypeToString(typeof(TestClass), formatting : Formatting.Indented);

注意事项:

  • 不寻常的契约(Contract),例如 JsonDynamicContractJsonISerializableContract尚未实现。

  • 如果 custom JsonConverter一直applied对于类型,没有直接的方法来生成默认序列化而不调用 WriteJson()并传入该类型的实例。

    可能能够使用FormatterServices.GetUninitializedObject(Type)在不调用构造函数的情况下生成您的类型的空实例,然后将其传递给 WriteJson() 以生成默认序列化。不能保证这会起作用。如果转换器希望通过正确调用构造函数来初始化集合等成员,则可能会抛出异常。

  • 同样,无法为实现 ISerializable 的类型生成默认序列化。没有实例。

  • 如果您使用驼峰式大小写,则可以为 resolver 参数传递 new CamelCasePropertyNamesContractResolver()

  • 在嵌套复杂对象的情况下,WriteDefaultValuesForType() 可以递归,但是在递归数据模型的情况下,您需要注意不要溢出堆栈。

  • 作为替代方法,您可以考虑生成并使用 在你的应用程序中。参见例如Generating Schemas .

演示 fiddle here .

关于c# - 我可以创建一个仅包含对象类型的空值的 JSON 示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57957797/

相关文章:

c# - 如何获取基类的泛型类型参数?

c# - 与串行端口 “Verifone VX520” 通信

json - 在对行执行删除操作后使用 table.ajax.reload() 时,表不会刷新

json - 如何将 jsonb 编码为 golang 中 http 响应的一部分

java - 从文件中获取 Json 以在 Java 中的 RESTful Post 请求中使用

java - JAVA中如何访问私有(private)内部类的私有(private)参数化方法

c# - 使用 C# 查看 MemberInfo 是否与 BindingFlags 匹配

c# - 在 C# 中返回对象的 JSON 数组

c# - 将 session 转换到对象

c# - 后退按钮的基于页面的操作