【发布时间】:2017-07-22 07:45:50
【问题描述】:
目前我偶然发现了 Newtonsofts Json 库的一个问题,这对我来说完全是个谜。
我有一些实现 IDynamicMetaObjectProvider 接口的类。将多个对象序列化为 json 没有问题,我从对象的每个实例中都得到了我期望的 json。
但是反序列化让我很头疼。从我目前观察到的情况来看,该库似乎正在缓存它无法找到的每个动态属性的值,并在应用程序运行时保留它。例如,我有以下三个 Json:
{ "PropA": "1" }
{ "PropA": "2", "PropB": "1" }
{ "PropA": "3", "PropB": "2", "PropC": "1" }
连续反序列化 Json 将为我提供以下 .NET 对象:
{ "PropA": "1" }
{ "PropA": "1", "PropB": "1" }
{ "PropA": "1", "PropB": "1", "PropC": "1" }
但是!如果我将目标类型从实现 IDynamicMetaObjectProvider 的目标类型更改为字典或简单的动态,反序列化的对象将具有正确设置的属性。
我的类有一个 index 属性,在 setter 上设置了一个断点,已经为 setter 提供了错误的值(所以我的类的实现没有问题)。
public abstract class DynamicModelObject : IDynamicMetaObjectProvider //, IPropertyIndexer //, IDictionary<String, Object>
{
[NotMapped]
[JsonIgnore]
internal Dictionary<String, Object> properties = new Dictionary<String, Object>();
[IgnoreProperty]
[JsonIgnore]
public override Object this[String propertyName]
{
get
{
object val;
if (properties.TryGetValue(propertyName, out val)) {
return val;
}
var prop = this.GetType().GetProperty(propertyName);
if (prop != null && prop.CanRead) {
return prop.GetValue(this);
}
return null;
}
set
{
isDearty = true;
var prop = this.GetType().GetProperty(propertyName);
if (prop != null && prop.CanWrite) {
prop.SetValue(this, value);
} else {
properties[propertyName] = value;
}
var val = value as String;
if (value == null || (val != null && String.IsNullOrEmpty(val))) {
properties.Remove(propertyName);
}
}
}
public DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
{
return new DynamicDictionaryPropertyStore<DynamicModelObject>(parameter, this);
}
[IgnoreProperty]
public IEnumerable<String> DynamicPropertyMemberNames
{
get
{
foreach (var key in properties.Keys) {
yield return key;
}
}
}
private List<String> staticProperties = null;
[IgnoreProperty]
private IEnumerable<String> StaticPropertyMemberNames
{
get
{
if (staticProperties == null) {
staticProperties = new List<String>();
foreach (var prop in this.GetType()
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty)) {
if (!Attribute.IsDefined(prop, typeof(IgnorePropertyAttribute)) && !Attribute.IsDefined(prop, typeof(ScriptIgnoreAttribute))) {
staticProperties.Add(prop.Name);
yield return prop.Name;
}
}
} else {
foreach (var prop in staticProperties) {
yield return prop;
}
}
}
}
[IgnoreProperty]
private IEnumerable<String> AllPropertyMemberNames
{
get
{
foreach (var prop in DynamicPropertyMemberNames.Concat(StaticPropertyMemberNames)) {
yield return prop;
}
}
}
private class DynamicDictionaryPropertyStore<T> : DynamicMetaObject where T : DynamicModelObject
{
private T target;
internal DynamicDictionaryPropertyStore(System.Linq.Expressions.Expression parameter, T target)
: base(parameter, BindingRestrictions.Empty, target)
{
this.target = target;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return target.DynamicPropertyMemberNames;
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
System.Linq.Expressions.Expression self = System.Linq.Expressions.Expression.Convert(Expression, LimitType);
if (binder == null) return null;
var body = System.Linq.Expressions.Expression.Property(self, "Item", System.Linq.Expressions.Expression.Constant(binder.Name));
var convert = System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression.Constant(value.Value), typeof(object));
var lambda = System.Linq.Expressions.Expression.Assign(body, convert);
return new DynamicMetaObject(lambda, restrictions);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
System.Linq.Expressions.Expression self = System.Linq.Expressions.Expression.Convert(Expression, LimitType);
if (binder == null) return null;
var body = System.Linq.Expressions.Expression.Property(self, "Item", System.Linq.Expressions.Expression.Constant(binder.Name));
return new DynamicMetaObject(body, restrictions);
}
}
}
怎么了??
【问题讨论】:
-
你能提供你的实现 IDynamicMetaObjectProvider 的类吗?