首页 > 解决方案 > 如何使用它的父接口序列化对象?

问题描述

使用 c# 8。我有一组具有默认实现的基本接口:

 public interface IEventBase
        {
            string PostRoutingKey { get; set; }
            string EventSource => Assembly.GetEntryAssembly()?.GetName().Name;
            long Timestamp => DateTimeOffset.UtcNow.ToUnixTimeSeconds();
            Guid EventId => Guid.NewGuid();
            string EventKey { get; set; }
        }
public interface IActionNotifiable : IEventBase
    {
        [JsonProperty(Required = Required.Always)]
        string SenderName { get; set; }
        [JsonProperty(Required = Required.Always)]
        string ReceiverName { get; set; }
        [JsonProperty(Required = Required.Always)]
        string SenderId { get; set; }
        [JsonProperty(Required = Required.Always)]
        string ReceiverId { get; set; }
        string Title { get; set; }
        string ShortDescription { get; set; }
        string LongDescription { get; set; }
        ActionNotifiableStatusEnum Status { get; set; }
        Dictionary<string, string> ExtraProperties { get; set; }
    }

 public interface IPush : IActionNotifiable
    {
        [JsonProperty(Required = Required.Always)]
        public string CallbackUrl { get; set; }
    }
public class DerivedConcretePush : IPush
{
    public string PostRoutingKey { get; set; }= string.Empty;
    public string EventKey { get; set; }= string.Empty;
    public string SenderName { get; set; }= string.Empty;
    public string ReceiverName { get; set; }= string.Empty;
    public string SenderId { get; set; }= string.Empty;
    public string ReceiverId { get; set; }= string.Empty;
    public string Title { get; set; }= string.Empty;
    public string ShortDescription { get; set; }= string.Empty;
    public string LongDescription { get; set; }= string.Empty;
    public ActionNotifiableStatusEnum Status { get; set; }
    public Dictionary<string, string> ExtraProperties { get; set; } = new Dictionary<string, string>();
    public string CallbackUrl { get; set; }= string.Empty; 
}

并尝试使用来自https://www.newtonsoft.com/json的 SerilizeObject 序列化对象,执行以下操作:

var message = JsonConvert.SerializeObject(@event, JsonConvertExtension.GetCamelCaseSettings());

我的 JsonSettings 看起来像这样:

public static JsonSerializerSettings GetCamelCaseSettings()
        {
            return new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                },
                Formatting = Formatting.Indented,
                TypeNameHandling = TypeNameHandling.Auto
            };
        }

我得到这样的东西:

{
  "postRoutingKey": "",
  "eventKey": "sericy-rabbiteventconsumer-cli.DerivedConcretePush",
  "senderName": "",
  "receiverName": "",
  "senderId": "",
  "receiverId": "",
  "title": "just a tittle",
  "shortDescription": "",
  "longDescription": "body",
  "status": 0,
  "extraProperties": {},
  "callbackUrl": ""
}

我曾尝试使用TypeNameHandling并将IEventBase类型传递给SerializeObject. 序列化包括所有接口属性的对象的最佳方法是什么?

标签: serialization.net-coreinterfacejson.netc#-8.0

解决方案


我最终创建了一个自定义合同解析器:

public class InterfaceContractResolver : DefaultContractResolver
    {
        private readonly Type[] _interfaceTypes;

        private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;

        public InterfaceContractResolver(params Type[] interfaceTypes)
        {
            _interfaceTypes = interfaceTypes;
            _typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
            NamingStrategy = new CamelCaseNamingStrategy();
        }

        protected override IList<JsonProperty> CreateProperties(
            Type type,
            MemberSerialization memberSerialization)
        {
            var typeToSerialize = _typeToSerializeMap.GetOrAdd(
                type,
                t => _interfaceTypes.FirstOrDefault(
                    it => it.IsAssignableFrom(t)) ?? t);

            var props = base.CreateProperties(typeToSerialize, memberSerialization);

            // mark all props as not ignored
            foreach (var prop in props)
            {
                prop.Ignored = false;
            }
            return props;
        }
    }


internal static class JsonConvertExtension
    {       {
        public static JsonSerializerSettings GetCamelCaseSettings()         public static JsonSerializerSettings SetupJsonSerializerSettings(Type eventType)
        {           {
           var eventTypes = eventType.GetParentTypes().ToArray();   
            return new JsonSerializerSettings               return new JsonSerializerSettings
            {               {
                ContractResolver = new DefaultContractResolver                  ContractResolver = new InterfaceContractResolver(eventTypes),
                {                   Formatting = Formatting.Indented,
                    NamingStrategy = new CamelCaseNamingStrategy()                  TypeNameHandling = TypeNameHandling.Auto,
                },  
                Formatting = Formatting.Indented    
            };              };

并使用以下类型调用它:

            var message = JsonConvert.SerializeObject(@event, JsonConvertExtension.SetupJsonSerializerSettings(@event.GetType()));

推荐阅读