【问题标题】:Serialize struct/class as a single string将结构/类序列化为单个字符串
【发布时间】:2019-01-29 21:17:43
【问题描述】:

我在 ViewModel 中使用了一个结构,以简化它们自动序列化的方式。我想将它的序列化为简单地调用.ToString() 方法。目前,当它被序列化为 JSON 时,它会变成:“{}”。这是我的日期类:

public struct Date
{
    private DateTime _date;

    public Date(DateTime date)
    {
        _date = date;
    }

    public static implicit operator Date(DateTime date) => new Date(date);

    public override string ToString() => _date.ToString("yyyy-MM-dd");
}

我认为可能有某种属性可以用来装饰结构,或者我可以实现某些接口,但它似乎没有帮助。

【问题讨论】:

  • 你用什么代码序列化成 JSON?
  • 作为@NetMage,有很多方法可以将对象序列化为 JSON,因此您需要将问题缩小到用于序列化的特定方式。 (请注意,大多数序列化方法不使用 .ToString(),因为 .ToString() 并非旨在创建具有往返能力的值表示)
  • 我只是用新的JsonResult(obj); 在控制器中返回对象。您的问题使我改进了搜索,并且我找到了有效的答案。我需要实现一个新的JsonConverter。我将发布我的解决方案作为答案。
  • 内置 (MVC) JsonResult 没有带参数的构造函数。 哪里这个JsonResult来自哪里?
  • 在构造函数中接受object 的内置JsonResult 位于Microsoft.AspNetCore.Mvc 命名空间中。

标签: c# json asp.net-core serialization


【解决方案1】:

很多时候,当项目更大时,很多课程都需要这样做。

我们需要双向转换。一个类应该使用ToString() 方法进行序列化,并且该类应该从String 中反序列化。我们使用以下约定。

定义标记接口,让类明确遵守它们支持使用 ToString 方法进行序列化并支持从字符串到对象实例的反序列化的约定。

    /// <summary>
    /// Interface to convert string to a type T
    /// </summary>
    public interface IStringToTypeConverter<out T>
    {
        T ConvertToType(string stringToConvertFrom);

    }

    /// <summary>
    /// Marker Interface to let Serialization/Deserialization work on the ToString Method of the class, Rather than
    /// calling on the Instance properties
    /// </summary>
    public interface ITypeToStringConverter
    {
    }

接下来,定义通用转换器,它将为实现上述接口的类进行转换(序列化/反序列化)。

    public class ToStringJsonConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {

            var isTypeImplementStringToTypeConverter = objectType.GetInterfaces().Any(x =>
                x == typeof(ITypeToStringConverter) ||
                (x.IsGenericType &&
                x.GetGenericTypeDefinition() == typeof(IStringToTypeConverter<>)));

            return isTypeImplementStringToTypeConverter;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteValue(value.ToString());
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // Load the JSON for the Result into a JObject

            var stringValue = reader.Value.ToString();

            if (string.IsNullOrWhiteSpace(stringValue))
            {
                var jObject = JObject.Load(reader);
                stringValue = jObject.ToString();

            }

            MethodInfo parse = objectType.GetMethod("ConvertToType");
            if (parse != null)
            {
                var destinationObject = Activator.CreateInstance(objectType,stringValue);
                return parse.Invoke(destinationObject, new object[] { stringValue });
            }

            throw new JsonException($"The {objectType.Name} type does not have a public ConvertToType(string) method.");
        }
    }

最后,将 Converter 添加到启动类中,并在 JSON 选项中传递它

services.AddMvc().AddJsonOptions(options =>
                {
                    options.SerializerSettings.Converters.Add(new ToStringJsonConverter());

                })

注意:请测试您的代码的性能基准,看看它是否对您的性能 SLA 有任何影响。

【讨论】:

    【解决方案2】:

    经过进一步研究,看起来 MVC 使用 JsonConverter 属性来序列化 JsonResults。下面的代码完成了我想做的事情。

    [JsonConverter(typeof(DateToString))]
    public struct Date
    {
        private DateTime _date;
    
        public Date(DateTime date)
        {
            _date = date;
        }
    
        public static implicit operator Date(DateTime date) => new Date(date);
    
        public override string ToString() => _date.ToString("yyyy-MM-dd");
    }
    
    public class DateToString : JsonConverter
    {
        public override bool CanConvert(Type objectType) => objectType == typeof(Date);
        public override bool CanRead => false;
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            => throw new NotImplementedException();
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
            writer.WriteValue(value.ToString());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-17
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多