基础 Class 序列化问题 - 不序列化派生 Class 属性
Base Class Serialization Issue - do not serialize Derived Class Properties
我厌倦了序列化相当大的实体列表,这些实体都是从基础 class 派生的。
我只需要客户端中的基本 class 属性。如何在不实例化基础 class?
的新实例的情况下实现此目的
我试过创建自定义 ContractResolver,但它似乎在运行时执行 getType(),而不是使用正在序列化的 list/Array 的类型
请参阅下面的代码示例。
我要实现。 castBaseString == actualBaseString ;
所以我希望 castBaseString = [{"Id":1},{"Id":2}]
而不是 [{"Value":"value","Id":1},{"Value":"value2","Id":2}]
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Tests {
[TestClass]
public class JsonNetTest {
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
class OtherDerived : Base {
public string Value { get; set; }
public string OtherValue { get; set; }
}
[TestMethod]
public void Test() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings();
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Assert.AreEqual(actualBaseString, castBaseString);
Assert.AreNotEqual(castBaseString, derString);
}
}
}
根据评论进行编辑
附加上下文:
为了清楚起见,我刚刚发布了这个简单的测试用例。
正在使用的实际上下文是在 aspnet 核心应用程序中。
假设有 3 个控制器
- /api/DerivedController/
- /api/OtherDerivedController/
- /api/BaseController/
当一个客户端调用1时,我们想要return一个Derived的列表,当一个客户端调用
2 我们想要 return OtherDerived 的列表,当他们调用 3,我们想要 return Base 的列表
数据存储在数据库中的 2 个不同表中 TBL_DERIVED 和 TBL_OTHERDERIVED。
当他们调用base时,我们想要实现的是return来自这些表中的一个或两个表的数据,但只是这些表的共同属性。
希望这能说明问题。
在 属性 的顶部添加 [JsonIgnore]
。
class Derived : Base {
[JsonIgnore]
public string Value { get; set; }
}
如果您不想使用属性,您可以使用 ContractResolver 强制仅对 Base
中的属性进行序列化:
public class DerivedTypeFilterContractResolver<T> : DefaultContractResolver {
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType != typeof(T)) {
property.ShouldSerialize = instance => false;
}
return property;
}
}
然后像这样使用它:
void Main() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings {
ContractResolver = new DerivedTypeFilterContractResolver<Base>()
};
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Console.WriteLine(castBaseString);
}
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
输出:
[{"Id":1},{"Id":2}]
事实证明,json 序列化的工作方式是不可能的。
@stuartd 答案可能是一个很好的解决方法,如果你只有有限的情况你想这样做。
我厌倦了序列化相当大的实体列表,这些实体都是从基础 class 派生的。 我只需要客户端中的基本 class 属性。如何在不实例化基础 class?
的新实例的情况下实现此目的我试过创建自定义 ContractResolver,但它似乎在运行时执行 getType(),而不是使用正在序列化的 list/Array 的类型
请参阅下面的代码示例。
我要实现。 castBaseString == actualBaseString ;
所以我希望 castBaseString = [{"Id":1},{"Id":2}]
而不是 [{"Value":"value","Id":1},{"Value":"value2","Id":2}]
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Tests {
[TestClass]
public class JsonNetTest {
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
class OtherDerived : Base {
public string Value { get; set; }
public string OtherValue { get; set; }
}
[TestMethod]
public void Test() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings();
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Assert.AreEqual(actualBaseString, castBaseString);
Assert.AreNotEqual(castBaseString, derString);
}
}
}
根据评论进行编辑
附加上下文:
为了清楚起见,我刚刚发布了这个简单的测试用例。
正在使用的实际上下文是在 aspnet 核心应用程序中。
假设有 3 个控制器
- /api/DerivedController/
- /api/OtherDerivedController/
- /api/BaseController/
当一个客户端调用1时,我们想要return一个Derived的列表,当一个客户端调用 2 我们想要 return OtherDerived 的列表,当他们调用 3,我们想要 return Base 的列表
数据存储在数据库中的 2 个不同表中 TBL_DERIVED 和 TBL_OTHERDERIVED。
当他们调用base时,我们想要实现的是return来自这些表中的一个或两个表的数据,但只是这些表的共同属性。
希望这能说明问题。
在 属性 的顶部添加 [JsonIgnore]
。
class Derived : Base {
[JsonIgnore]
public string Value { get; set; }
}
如果您不想使用属性,您可以使用 ContractResolver 强制仅对 Base
中的属性进行序列化:
public class DerivedTypeFilterContractResolver<T> : DefaultContractResolver {
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType != typeof(T)) {
property.ShouldSerialize = instance => false;
}
return property;
}
}
然后像这样使用它:
void Main() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings {
ContractResolver = new DerivedTypeFilterContractResolver<Base>()
};
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Console.WriteLine(castBaseString);
}
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
输出:
[{"Id":1},{"Id":2}]
事实证明,json 序列化的工作方式是不可能的。 @stuartd 答案可能是一个很好的解决方法,如果你只有有限的情况你想这样做。