gpt4 book ai didi

c# - 如何使用 JSON.NET 在 C# 中序列化 PSObjects?

转载 作者:太空狗 更新时间:2023-10-29 23:19:59 25 4
gpt4 key购买 nike

我正在编写 Cmdlet,需要将对象结构传递到可能包含 PSObject 的 API 客户端。目前,这些序列化为包含 CLIXML 的 JSON 字符串。相反,我需要将其视为一个对象(包括 PSObject.Properties 中的 NoteProperties 作为属性,并递归地序列化它们的值)。

我尝试编写自己的 JsonConverter 但出于某种原因,它只会被调用用于顶级对象,而不是用于嵌套的 PSObject:

public class PSObjectJsonConverter : JsonConverter {

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
if (value is PSObject) {
JObject obj = new JObject();
foreach (var prop in ((PSObject)value).Properties) {
obj.Add(new JProperty(prop.Name, value));
}
obj.WriteTo(writer);
} else {
JToken token = JToken.FromObject(value);
token.WriteTo(writer);
}
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
throw new NotImplementedException();
}

public override bool CanRead {
get { return false; }
}

public override bool CanConvert(Type objectType) {
return true;
}
}

此外,我使用 CamelCasePropertyNamesContractResolver 将序列化为驼峰式大小写。有没有办法让转换器遵守这一点?

最佳答案

以下转换器应正确序列化 PSObject 类型的递归嵌套对象:

public class PSObjectJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(PSObject).IsAssignableFrom(objectType);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var psObj = (PSObject)value;
writer.WriteStartObject();
foreach (var prop in psObj.Properties)
{
//Probably we shouldn't try to serialize a property that can't be read.
//https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
if (!prop.IsGettable)
continue;
writer.WritePropertyName(prop.Name);
serializer.Serialize(writer, prop.Value);
}
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override bool CanRead { get { return false; } }
}

注意事项:

  • WriteJson您将传入对象 value 序列化为每个属性的值。你肯定是说 prop.Value .

  • 仅从 CanConvert() 返回 true当传入的对象类型是 PSObject 类型时,您无需在 WriteJson() 中为非 PSObject 类型实现默认序列化。

  • 当您调用 JToken.FromObject(value) 时,您没有使用传入的 JsonSerializer 序列化程序。因此,任何 JsonSerializerSettings(包括转换器)都将丢失。理论上你可以使用 JToken.FromObject(Object, JsonSerializer)相反,这会保留设置,但如果这样做,您会遇到 JSON.Net throws StackOverflowException when using [JsonConvert()] 中描述的错误。幸运的是,由于我们现在在需要默认序列化时从 CanConvert 返回 false,因此不再需要这样做。

  • 无需构造中间JObject。您可以直接写入 JsonWriter,这样性能会更高一些。

更新:此外,我使用 CamelCasePropertyNamesContractResolver 将序列化为驼峰式大小写。有没有办法让转换器遵守这一点?

一旦你介绍了一个custom JsonConverter对于您的类型,您需要手动执行所有操作,包括属性名称的重新映射。这是 WriteJson() 的一个版本,它使用 DefaultContractResolver.NamingStrategy 来处理这个问题:

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var psObj = (PSObject)value;
writer.WriteStartObject();
var resolver = serializer.ContractResolver as DefaultContractResolver;
var strategy = (resolver == null ? null : resolver.NamingStrategy) ?? new DefaultNamingStrategy();

foreach (var prop in psObj.Properties)
{
//Probably we shouldn't try to serialize a property that can't be read.
//https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
if (!prop.IsGettable)
continue;
writer.WritePropertyName(strategy.GetPropertyName(prop.Name, false));
serializer.Serialize(writer, prop.Value);
}
writer.WriteEndObject();
}

请注意,命名策略是在 Json.NET 9.0.1 中引入的因此,如果您使用的是早期版本,则需要创建自己的驼峰命名映射器,例如 this answer 中所示的映射器。 .

关于c# - 如何使用 JSON.NET 在 C# 中序列化 PSObjects?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52129810/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com