序列化/反序列化对象,并保留对象的每种字段类型

时间:2019-01-01 05:36:39

标签: c# json.net

我正在编写一个实用程序,该实用程序读取文本文件(json)并动态构造一个json对象并将其发送到REST API。为了实现这一点,我希望我的序列化json对象(我​​在C#中使用Json.Net创建了该对象)也保留每个字段的类型信息及其值。

例如,我希望我的json文件采用类似格式:

{
    "fieldString": {
        "type": "string",
        "value": "my custom string data"
    },
    "fieldTimeStamp": {
        "type": "date",
        "value": "2018-12-10T08:25:55.150Z"
    },
    "fieldNumber": {
        "type": "number",
        "value": 999999.999
    },
    "fieldGeopoint": {
        "type": "geopoint",
        "value": {
            "_latitude": 0.0,
            "_longitude": 0.0
        }
    },
}

感谢社区成员提出的问题,这是其他信息,希望对您有所帮助...

我的实用程序将是数据上传实用程序,它将独立于任何应用程序读取数据。这将从json文件中读取数据,并构造一个正确的对象以调用REST API(任意)。例如GeoPoint对象,它不是原始数据类型,并且不同的语言可能具有与此对象关联的不同名称和属性。

创建json文件的工具将负责提供键入的信息以及每个对象的字段值。我的数据上传实用程序将决定如何解释将GeoPoint传递给其他API的方法,例如,在Azure CosmosDB中,geopoint称为“ Point”,而在好世界中,geopoint称为“ GeoPoint”,其他人可能会有不同相同基础信息的名称。或者例如,有些可以区分“ int”和“ float”,而另一些则不能。

2 个答案:

答案 0 :(得分:0)

这已经是JSON.Net序列化程序中内置的功能:

How to serialize object to json with type info using Newtonsoft.Json?

我相信您可以利用这一点:区别实际上是原始类型和对象类型之间的区别。如果您有一个object属性,则它是原始类型(也许不是)将被支持。因此,您需要为每种原始类型创建一个单独的类。您将创建自己的String对象,Date对象,Number对象等等(在C#端)。

此外,您可以直接使用JsonWriter / JsonReader。它们不太难使用,并且将为您提供对协议的最佳控制。直接代码将使其易于调试,并且还会产生性能非常好的副作用。 (通常,JSON.net使用反射和/或运行时编译的帮助程序类)

答案 1 :(得分:0)

尽管我按照@ZoharPeled的建议使用Json Schema路径。

但是正如@Todd所建议的那样,我创建了以下解决方案,该解决方案在序列化对象时保留字段的对象类型信息。我将其放在此处仅供参考,以防万一有人要引用它。

    class TypeInfoConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return true;
        }

        public override bool CanRead
        {
            get { return 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)
        {
            var converters = serializer.Converters.Where(x => !(x is TypeInfoConverter)).ToArray();
            JToken jToken = JToken.FromObject(value);
            JObject jObject;
            switch (jToken.Type)
            {
                case JTokenType.Object:
                case JTokenType.Array:
                case JTokenType.Bytes:
                case JTokenType.Date:
                    jObject = JObject.FromObject(new Converter(value));
                    jObject.WriteTo(writer, converters);
                    break;
                default:
                    //jObject = JObject.FromObject(new Converter(value));
                    //jObject.WriteTo(writer);
                    jToken.WriteTo(writer);
                    break;
            }
        }

        class Converter
        {
            public Dictionary<string, object> _attr = new Dictionary<string, object>();
            public object value;

            public Converter(object value)
            {
                this.value = value;
                addAttributes();
            }

            private void addAttributes()
            {
                Type t = value.GetType();
                _attr["type"] = t.Name;

                if (t.IsGenericType
                    && (value is IList || value is IDictionary))
                {
                    collectionAttributes(value, _attr, t);
                }
                else if (t.IsEnum)
                {
                    _attr["type"] = "enum";
                    _attr["class"] = t.Name;
                    //attributes["meaning"] = value.ToString();
                }
            }

            private void collectionAttributes(object value, Dictionary<string, object> attr, Type type)
            {

                Dictionary<string, object> o = new Dictionary<string, object>();
                if (value is IDictionary && value.GetType().IsGenericType)
                {
                    attr["type"] = "map";
                    attr["key"] = type.GetGenericArguments()[0].Name;
                    if(type.GetGenericArguments()[1].IsGenericType == true)
                    {
                        collectionAttributes(((IDictionary)value).Values, o, type.GetGenericArguments()[1]);
                        attr["value"] = o;
                    }
                    else
                    {
                        attr["value"] = type.GetGenericArguments()[1].Name;
                    }
                }
                else if (value is ICollection && type.IsGenericType)
                {
                    attr["type"] = "array";
                    if (type.GetGenericArguments()[0].IsGenericType == true)
                    {
                        collectionAttributes(value, o, type.GetGenericArguments()[0]);
                        attr["value"] = o;
                    }
                    else
                    {
                        attr["of"] = type.GetGenericArguments()[0].Name;
                    }
                }
            }
        }

用法

class TrialObject
    {
        [JsonConverter(typeof(TypeInfoConverter))]
        public String szObject = "trial string";

        [JsonConverter(typeof(TypeInfoConverter))]
        public Double doubleObject = 999999999.999;

        [JsonConverter(typeof(TypeInfoConverter))]
        public Boolean boolObject = true;

        [JsonConverter(typeof(TypeInfoConverter))]
        public DateTime dateObject = DateTime.Now;

        [JsonConverter(typeof(TypeInfoConverter))]
        public GeoPoint geoPointObject = new GeoPoint() { Latitude = 123456789.123456, Longitude = 123456789.123456 };

        [JsonConverter(typeof(TypeInfoConverter))]
        public Dictionary<string, string> mapObject = new Dictionary<string, string>();

        [JsonConverter(typeof(TypeInfoConverter))]
        public Dictionary<string, List<GeoPoint>> mapObjectEx = new Dictionary<string, List<GeoPoint>>()
            {{ "1", new List<GeoPoint>() { new GeoPoint() { Latitude = 0.0, Longitude = 0.0 } } }};

        [JsonConverter(typeof(TypeInfoConverter))]
        public List<GeoPoint> points = new List<GeoPoint>()
            { new GeoPoint() { Latitude=0.0, Longitude=0.0 } };

        [JsonConverter(typeof(TypeInfoConverter))]
        public Rating rating = Rating.Good;
    }

    class GeoPoint
    {
        public double Latitude;
        public double Longitude;
    }

    enum Rating
    {
        Good,
        Bad,
    }