![](/img/trans.png)
[英]C# Xml Serialization: Serialize Class properties as attributes to the parent class
[英]C# Serialize Protected Attributes from parent-class - issue
我已經實現了一個帶有“自定義”ContractResolver 的 JsonSerializer,它覆蓋了綁定標志,因此我實際上可以序列化私有成員和受保護成員。 因為我想序列化特定類中的對象。 讓一切都“公開”不是一種選擇。
所以我實現了幾乎可以正常工作的代碼,用於相同 class 上的屬性。 但是,當涉及到來自父類的受保護屬性時,它會在名為“k__Backingfield”的 JSON 字符串中生成一些奇怪的額外信息。
首先,結果/問題:
json-debug:
{
"jsonTestPrivate":"child-class",
"jsonTestProtected":"Attr from parent class",
"<jsonTestPrivate>k__BackingField":"child-class" //<<--- I want to get rid of THIS :(
}
這個問題似乎只發生在受父類保護的派生屬性上。
--
編碼:
namespace XYZ
{
class CustomJsonSerializerSettings : Newtonsoft.Json.Serialization.DefaultContractResolver
{
public CustomJsonSerializerSettings ContractResolver = null;
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(p => base.CreateProperty(p, memberSerialization))
.Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(f => base.CreateProperty(f, memberSerialization)))
.ToList();
props.ForEach(p => { p.Writable = true; p.Readable = true; });
return props;
}
}
}
我的父類抽象了必須在每個可序列化 Object 中引入的 SerializeJson function 並提供了導致問題的父屬性:
namespace XYZ
{
public abstract class CommandResponse
{
public abstract string SerializeJson();
protected string jsonTestProtected { get; set; } = "Attr from parent class";
//Helper class to serialize/unserialize objects on higher scope.
//Just derive from this class for every JSON-response/able object and implement abstract function
}
}
我的子類實現了實際的 function,包括對我已經測試過的東西的一些評論。
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Converters;
namespace XYZ
{
class CommandActionInvalid : CommandResponse
{
private string jsonTestPrivate { get; set; } = "child-class";
public override string SerializeJson()
{
DefaultContractResolver resolverObj = new CustomJsonSerializerSettings();
//This attributes dont seem to do anything, even if referenced alot in stackoverflow :(
/*
resolverObj.IgnoreSerializableAttribute = true;
resolverObj.IgnoreSerializableInterface = true;
resolverObj.IgnoreShouldSerializeMembers = true;
resolverObj.SerializeCompilerGeneratedMembers = false;
*/
var settings = new JsonSerializerSettings() { ContractResolver = resolverObj };
return JsonConvert.SerializeObject(this, settings);
}
}
}
k__Backingfield
字段是秘密的、編譯器生成的自動實現屬性的支持字段。 如果您想在序列化所有其他字段和屬性時跳過它們,您的自定義合同解析器可以重寫如下:
class CustomJsonContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
const BindingFlags allInstanceMembersFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
IEnumerable<MemberInfo> fields =
objectType.GetFields(allInstanceMembersFlags)
// Skip k__BackingField secret backing fields of auto-implemented properties.
.Where(fi => !fi.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)));
IEnumerable<MemberInfo> props = objectType.GetProperties(allInstanceMembersFlags)
// Skip indexed properties like List[0].
.Where(pi => pi.GetIndexParameters().Length == 0);
return fields.Concat(props).ToList();
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
switch (member)
{
case FieldInfo fi:
// Passing MemberSerialization.Fields causes the JsonProperty to be marked as readable and writable
return base.CreateProperty(fi, MemberSerialization.Fields);
case PropertyInfo pi:
var jsonProperty = base.CreateProperty(pi, memberSerialization);
// Mark the property as readable and writable if the corresponding get and set methods exist even if not public
if (pi.GetGetMethod(true) != null)
jsonProperty.Readable = true;
if (pi.GetSetMethod(true) != null)
jsonProperty.Writable = true;
return jsonProperty;
default:
return base.CreateProperty(member, memberSerialization);
}
}
}
筆記:
檢查字段是否為秘密支持字段的方法取自Marc Gravell的這個答案,以確定 FieldInfo 是否是編譯器生成的支持字段。
如果存在相應的 get- 和 set- 方法,則只應設置JsonProperty.Readable
和JsonProperty.Writable
。 如果您無條件地設置它們,您的代碼將在序列化具有僅設置屬性的類型時崩潰,例如
protected string jsonTestProtectedSetOnlyProperty { set { jsonTestProtected = value; } }
我不建議完全替換CreateProperties()
的邏輯,因為基本 class 方法包含您最終會忽略的邏輯,例如在屬性名稱表中緩存屬性名稱。
您需要過濾掉索引屬性,因為這些屬性無法序列化。
您可能希望使用BindingFlags.FlattenHierarchy
指定應返回層次結構上的公共和受保護 static 成員。
我將您的 class 從CustomJsonSerializerSettings
重命名為CustomJsonContractResolver
因為它是一個自定義合同解析器,它被傳遞到settings 中,而不是設置自己。
Newtonsoft 建議靜態緩存和重用合約解析器以獲得最佳性能。
有關秘密支持字段的更多信息,請參閱是否可以訪問自動實現屬性后面的支持字段? .
此合同解析程序可能無法正常用於數據合同類型等選擇加入合同。 如果您的任何類型都有選擇加入的合同,您可能需要指定如何序列化這些合同並進行測試以查看您是否獲得了所需的結果。
演示小提琴在這里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.