fel*_*ker 5 c# powershell json.net
我正在编写一个Cmdlet,需要将对象结构传递给可能包含PSObject
s 的API客户端.目前,这些序列化作为包含CLIXML的JSON字符串.相反,我需要将它视为一个对象(包括PSObject.Properties
作为属性的NoteProperties ,并递归地序列化它们的值).
我尝试编写自己的,JsonConverter
但由于某种原因,它只被调用顶级对象,而不是嵌套PSObject
s:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
另外,我正在使用序列化来使用驼峰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://docs.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; } }
}
Run Code Online (Sandbox Code Playgroud)
笔记:
在WriteJson
您将传入对象序列化为value
每个属性的值时。你的意思肯定是prop.Value
。
通过只返回true
从CanConvert()
当输入的对象类型为类型的PSObject
,你避免了需要实施的默认序列化非PSObject
类型WriteJson()
。
当你打电话时,JToken.FromObject(value)
你没有使用传入的JsonSerializer serializer
. 因此,任何JsonSerializerSettings
(包括转换器)都将丢失。从理论上讲,您可以JToken.FromObject(Object, JsonSerializer)
改用,这将保留设置,但如果您这样做了,您会遇到JSON.Net 中描述的错误,在使用 [JsonConvert()] 时抛出 StackOverflowException。幸运的是,由于我们现在false
从CanConvert
需要默认序列化时返回,因此不再需要。
无需构建中间体JObject
。您可以直接写入JsonWriter
,这会提高一些性能。
更新:此外,我正在使用CamelCasePropertyNamesContractResolver
. 有没有办法让转换器尊重这一点?
一旦为您的类型引入自定义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://docs.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();
}
Run Code Online (Sandbox Code Playgroud)
请注意,命名策略是在Json.NET 9.0.1中引入的,因此如果您使用的是早期版本,则需要创建自己的驼峰命名映射器,例如本答案中所示的映射器。
归档时间: |
|
查看次数: |
335 次 |
最近记录: |