首页 > 编程知识 正文

C# 使用 JObject 转换 类与Json文本

时间:2023-05-05 23:51:31 阅读:237899 作者:214

之前对Json的使用中,Newtonsoft.Json.JsonConvert 的序列化与反序列化基本就能满足需求了。今天大佬突发奇想,他想要一个info文件,里面存储着某个单位的各种信息,它们可能是某个字段,也可能是某个类的信息。虽然嘴上说着不愿意,但大佬说的还是得做不是,于是查询资料之后就注意到了这个之前没看到的家伙:JObject。

JObject Class

   首先,我们还是要了解一下 JObject 是个啥,官方文档我就不摘录了,有兴趣的可以去看下。 psdmy!
还是先说说自己的理解吧,在我的角度来看,JObject 是对 Json 文件格式的一次封装,让我们可以将多个类转化成字符串存储在一个Json文件中。它作为一个Json工具,十分契合之前大佬提出的想法,实践之后,它也确实能够完成大佬所需的功能。

对其中几个函数的理解

   我们常用到的几个函数,这边稍微整理了下,随时补充,

1、FromObject:可以将object转化成需要的 JObject 对象。
2、Parse: 可以将Json 字符串 转化成需要的 JObject 对象。
3、Add:向 JObject 对象中添加一个 键值对,key是string,value 是 JToken 对象(下面我们会说到)。psdmy!
4、ContainsKey、 GetValue 、TryGetValue、Remove:这四个和上面的 Add 一样,类似我们的 字典(Dictionary)操作,分别是 是否包含该键,取值、尝试取值与移除该键对应键值对 的作用。
5、Properties:返回所有的键值对集合,可以用 foreach 将其中的内容(item.name 与 item.value)取出。
6、this[string propertyName]:通过 索引器 [ ] 取值。
7、最后,也是我没能搞懂的一个,就是它自己的构造函数了,明明提供了object 参数(还有object参数数组)的构造重载,但我传类参数进去却转换报错。想想其实也对,只传一个object,它也不知道键是啥呀(虽然我之后会写键就是类名的扩展,但那毕竟是自己写的扩展不是,官方不能这么武断)。

JToken :

简单的来说,它是 JObject 键值对中的那个值。我们可以使用它带的几个函数方便的实现类的转换。
首先,和JObject 一样, FromObject()与Parse()可以很轻易的获取到JToken对象(参数对了的话) 。
然后就是 ToObject<T> ()函数了,可以用来将自身转化成需要的object对象。
当然,JToken的一系列隐式转换让我们可以在添加JObject的值的时候,可以直接添加 string、float等类型。

一些奇怪的地方:

1、之前说过的构造函数问题。
2、JObject 为了能够 包含 自身,做到多层次的 Json 效果,自己继承了 JContainer,即继承了JToken。这样的话,JObject 就能够直接使用很多 JToken中的函数,像 AddAfterSelf。但因为缺乏键的存在,转换又不能成功,导致会 报 “ArgumentException: Could not determine JSON object type for type ClassA.” 这种错误。

针对添加 object 类会报错的问题,我写了两个拓展函数,能够方便的添加或取出 object 对象。
当然,也很有可能是我没用对它提供的函数(毕竟人家不会提供一个没有用的函数接口在那放着),若是看到这的小伙子能搞懂了,还希望能留个言交流一下,告知一二。

2019.11.4 修正:对不起,我傻了,明明可以用 JToken.FromObject() 直接构造 JToken 的, 我竟然还用上了反射。下面的Add扩展可以用 obj.Add(name, JToken.FromObject(obj)) 直接替换 。

public static class JsonLinqExt{ /// <summary> /// 向 JObject 中添加 object 类型 /// </summary> /// <param name="_jobj">JObject自身</param> /// <param name="_name">object需要设置的key</param> /// <param name="_obj">object对象</param> public static void Add(this JObject _jobj, string _name, object _obj) { JObject valueObj = new JObject(); // 避免添加属性自带的私有变量, 还是不要带上私有字段了 BindingFlags flags = /*BindingFlags.NonPublic |*/ BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static; Type type = _obj.GetType(); FieldInfo[] fields = type.GetFields(flags); // 获取字段 foreach (FieldInfo field in fields) { valueObj.Add(field.Name, JToken.FromObject(field.GetValue(_obj))); } PropertyInfo[] properties = type.GetProperties(flags); // 获取属性 foreach (PropertyInfo propertie in properties) { valueObj.Add(propertie.Name, JToken.FromObject(propertie.GetValue(_obj))); } if (!_jobj.ContainsKey(_name)) _jobj.Add(_name, valueObj); // 保证不重复添加 else Debug.LogError($"{type.Name} 重复添加"); } /// <summary> /// 取出 JObject 中的 object 对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="_jObj">JObject</param> /// <param name="_keyName">对象的keyName</param> /// <param name="_obj">object对象</param> /// <returns></returns> public static bool TryGetValue<T>(this JObject _jObj, string _keyName, out T _obj) { _obj = default; // 通过需要的参数类型名, 拿到 _jObj 中相应的 value if (_jObj.TryGetValue(_keyName, out JToken jToken)) { if (typeof(T).IsValueType) { _obj = jToken.Value<T>(); } else { _obj = jToken.ToObject<T>(); } return true; } return false; }}

这边用到了一些反射的机制,取出了类中的字段与属性,分别赋值。

哎,说到反射,不得不岔个话题提一下之前写 利用反射 写深拷贝的时候遇到的问题。数组的深拷贝 以及 Json 存储时的 Vector3 序列化的问题。以后有机会再说吧,今天就先到这儿吧,溜了溜了~

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。