使用 json.net 中的非 public setter 反序列化 public 属性
Deserializing public property with non-public setter in json.net
假设我有以下 class -
public class A
{
public int P1 { get; internal set; }
}
使用 json.net,我可以使用 P1 属性 序列化类型。但是,在反序列化过程中,P1 未设置。在不修改 class A 的情况下,是否有构建方法来处理这个问题?就我而言,我正在使用来自不同程序集的 class 并且无法修改它。
是的,您可以使用自定义 ContractResolver
使内部 属性 可写到 Json.Net。这是您需要的代码:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (member.DeclaringType == typeof(A) && prop.PropertyName == "P1")
{
prop.Writable = true;
}
return prop;
}
}
要使用解析器,请创建 JsonSerializerSettings
的实例并将其 ContractResolver
属性 设置为自定义解析器的新实例。然后,将设置传递给 JsonConvert.DeserializeObject<T>()
.
演示:
class Program
{
static void Main(string[] args)
{
string json = @"{ ""P1"" : ""42"" }";
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
A a = JsonConvert.DeserializeObject<A>(json, settings);
Console.WriteLine(a.P1);
}
}
输出:
42
Fiddle: https://dotnetfiddle.net/1fw2lC
这是我处理更一般情况的解决方案:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty result = base.CreateProperty(member, memberSerialization);
var propInfo = member as PropertyInfo;
result.Writable |= propInfo != null
&& propInfo.CanWrite
&& !propInfo.IsPrivate;
return result;
}
}
使用 class CInternalSetter:
class CInternalSetter
{
public CInternalSetter()
{
LoggedEmployeeId3 = 10;
}
public int LoggedEmployeeId { get; set; }
public int LoggedEmployeeId2 { get; internal set; }
public int LoggedEmployeeId3 { get; }
public override string ToString()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
}
然后用这个 class:
来测试它
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
var c = new CInternalSetter()
{
LoggedEmployeeId = 1,
LoggedEmployeeId2 = 2
};
var cString = JsonConvert.SerializeObject(c);
Console.WriteLine(cString);
Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString).ToString());
Console.WriteLine("-------------------------------------------");
Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString, settings).ToString());
经过一些实验后,我发现如果用以下方式装饰 属性,属性 会正确反序列化:
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
应用于原题中的class:
public class A
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
public int P1 { get; internal set; }
}
假设我有以下 class -
public class A
{
public int P1 { get; internal set; }
}
使用 json.net,我可以使用 P1 属性 序列化类型。但是,在反序列化过程中,P1 未设置。在不修改 class A 的情况下,是否有构建方法来处理这个问题?就我而言,我正在使用来自不同程序集的 class 并且无法修改它。
是的,您可以使用自定义 ContractResolver
使内部 属性 可写到 Json.Net。这是您需要的代码:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (member.DeclaringType == typeof(A) && prop.PropertyName == "P1")
{
prop.Writable = true;
}
return prop;
}
}
要使用解析器,请创建 JsonSerializerSettings
的实例并将其 ContractResolver
属性 设置为自定义解析器的新实例。然后,将设置传递给 JsonConvert.DeserializeObject<T>()
.
演示:
class Program
{
static void Main(string[] args)
{
string json = @"{ ""P1"" : ""42"" }";
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
A a = JsonConvert.DeserializeObject<A>(json, settings);
Console.WriteLine(a.P1);
}
}
输出:
42
Fiddle: https://dotnetfiddle.net/1fw2lC
这是我处理更一般情况的解决方案:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty result = base.CreateProperty(member, memberSerialization);
var propInfo = member as PropertyInfo;
result.Writable |= propInfo != null
&& propInfo.CanWrite
&& !propInfo.IsPrivate;
return result;
}
}
使用 class CInternalSetter:
class CInternalSetter
{
public CInternalSetter()
{
LoggedEmployeeId3 = 10;
}
public int LoggedEmployeeId { get; set; }
public int LoggedEmployeeId2 { get; internal set; }
public int LoggedEmployeeId3 { get; }
public override string ToString()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
}
然后用这个 class:
来测试它JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
var c = new CInternalSetter()
{
LoggedEmployeeId = 1,
LoggedEmployeeId2 = 2
};
var cString = JsonConvert.SerializeObject(c);
Console.WriteLine(cString);
Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString).ToString());
Console.WriteLine("-------------------------------------------");
Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString, settings).ToString());
经过一些实验后,我发现如果用以下方式装饰 属性,属性 会正确反序列化:
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
应用于原题中的class:
public class A
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
public int P1 { get; internal set; }
}