我们正在使用 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),例如
JsonDynamicContract
或JsonISerializableContract
尚未实现。如果 custom
JsonConverter
一直applied对于类型,没有直接的方法来生成默认序列化而不调用WriteJson()
并传入该类型的实例。您可能能够使用
FormatterServices.GetUninitializedObject(Type)
在不调用构造函数的情况下生成您的类型的空实例,然后将其传递给WriteJson()
以生成默认序列化。不能保证这会起作用。如果转换器希望通过正确调用构造函数来初始化集合等成员,则可能会抛出异常。同样,无法为实现
ISerializable
的类型生成默认序列化。没有实例。如果您使用驼峰式大小写,则可以为
resolver
参数传递new CamelCasePropertyNamesContractResolver()
。在嵌套复杂对象的情况下,
WriteDefaultValuesForType()
可以递归,但是在递归数据模型的情况下,您需要注意不要溢出堆栈。作为替代方法,您可以考虑生成并使用 jsonschema在你的应用程序中。参见例如Generating Schemas .
演示 fiddle here .
关于c# - 我可以创建一个仅包含对象类型的空值的 JSON 示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57957797/