Dynamic动态Json解析帮助类,C#动态解析JSON方法,
不用model直接解析JSON,方便快捷的首选方式,
Dynamic动态解析JSON代码量最起码减少一半
DynJsonHelper 全称为DynamicJsonHelper
中文简称:动态Json解析帮助类
开始封装时间:2016.3.30(持续更新中)
适用版本:.NET Framework 4.0以上版本(包含.NET4.0)
核心技术:运用Dynamic特性将json字符串自动转换为Dynamic Object实现动态解析json数组
核心理念:采用动态解析json数据的方式,去除.Net中对Model实体对象封装,
达到节约时间成本、精简代码、提高开发效率的目的
调用方法:暂时封装了两个实用方法
Json字符串转为Json对象 : DynJsonHelper.ToObject(Json字符串);
数组/对象转为Json字符串:DynJsonHelper.ToJson(数组/对象);
DynJsonHelper源码下载
001 | using System; |
002 | using System.Collections; |
003 | using System.Collections.Generic; |
004 | using System.Diagnostics; |
005 | using System.Dynamic; |
006 | using System.IO; |
007 | using System.Linq; |
008 | using System.Reflection; |
009 | using System.Runtime.Serialization.Json; |
010 | using System.Text; |
011 | using System.Xml; |
012 | using System.Xml.Linq; |
013 |
014 | namespace AutoHome.JsonDynamic |
015 | { |
016 | /** |
017 | * DynJsonHelper 全称为DynamicJsonHelper |
018 | * 中文简称:动态Json解析帮助类 |
019 | * 开始封装时间:2016.3.30(持续更新中) |
020 | * 适用版本:.NET Framework 4.0以上版本(包含.NET4.0) |
021 | * 核心技术:运用Dynamic特性将json字符串自动转换为Dynamic Object实现动态解析json数组 |
022 | * 核心理念:采用动态解析json数据的方式,去除.Net中对Model实体对象封装, |
023 | * 达到节约时间成本、精简代码、提高开发效率的目的 |
024 | * 调用方法:暂时封装了两个实用方法 |
025 | * Json字符串转为Json对象 : DynJsonHelper.ToObject(Json字符串); |
026 | * 数组/对象转为Json字符串:DynJsonHelper.ToJson(数组/对象); |
027 | * |
028 | * |
029 | * **/ |
030 | public class DynJsonHelper : DynamicObject |
031 | { |
032 |
033 | #region Json操作方法 |
034 | /// <summary> |
035 | /// 把Json字符串转为Json对象 |
036 | /// </summary> |
037 | /// <param name="json">String类型 符合Json规范的字符串</param> |
038 | /// <returns>Json对象或Json数组List</returns> |
039 | public static dynamic ToObject( string json) |
040 | { |
041 | return ToObject(json, Encoding.Unicode); |
042 | } |
043 | /// <summary> |
044 | /// 把Json字符串转为Json对象(可自定义编码) |
045 | /// </summary> |
046 | /// <param name="json">String类型 符合Json规范的字符串</param> |
047 | /// <param name="encoding">自定义编码</param> |
048 | /// <returns>Json对象或Json数组List</returns> |
049 | public static dynamic ToObject( string json, Encoding encoding) |
050 | { |
051 | try |
052 | { |
053 | using (var reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max)) |
054 | { |
055 | return ToValue(XElement.Load(reader)); |
056 | } |
057 | } |
058 | catch (Exception exc) { return exc.Message; } |
059 | } |
060 | /// <summary> |
061 | /// 把Stream类型的Json数据转为Json对象 |
062 | /// </summary> |
063 | /// <param name="stream">Stream类型Json数据</param> |
064 | /// <returns>Json对象或Json数组List</returns> |
065 | public static dynamic ToObject(Stream stream) |
066 | { |
067 | try |
068 | { |
069 | using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max)) |
070 | { |
071 | return ToValue(XElement.Load(reader)); |
072 | } |
073 | } |
074 | catch (Exception exc) { return exc.Message; } |
075 | } |
076 | /// <summary> |
077 | /// 把Stream类型的Json数据转为Json对象 |
078 | /// </summary> |
079 | /// <param name="stream">Stream类型Json数据</param> |
080 | /// <param name="encoding">自定义编码</param> |
081 | /// <returns>Json对象或Json数组List</returns> |
082 | public static dynamic ToObject(Stream stream, Encoding encoding) |
083 | { |
084 | try |
085 | { |
086 | using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, encoding, XmlDictionaryReaderQuotas.Max, _ => { })) |
087 | { |
088 | return ToValue(XElement.Load(reader)); |
089 | } |
090 | } |
091 | catch (Exception exc) { return exc.Message; } |
092 | } |
093 | /// <summary> |
094 | /// 把对象或者List数组转为Json字符串(支持复杂对象转换) |
095 | /// </summary> |
096 | /// <param name="obj">object</param> |
097 | /// <returns>Json字符串</returns> |
098 | public static string ToJson( object obj) |
099 | { |
100 | return CreateJsonString( new XStreamingElement( "root" , CreateTypeAttr(GetJsonType(obj)), CreateJsonNode(obj))); |
101 | } |
102 | #endregion |
103 |
104 | #region 私有方法 |
105 | /// <summary> |
106 | /// 枚举定义Json类型 |
107 | /// </summary> |
108 | private enum JsonType |
109 | { |
110 | @ string , number, boolean, @ object , array, @ null |
111 | } |
112 | /// <summary> |
113 | /// 处理不同类型的Value |
114 | /// </summary> |
115 | /// <param name="element"></param> |
116 | /// <returns></returns> |
117 | private static dynamic ToValue(XElement element) |
118 | { |
119 | var type = (JsonType)Enum.Parse( typeof (JsonType), element.Attribute( "type" ).Value); |
120 | switch (type) |
121 | { |
122 | case JsonType.boolean: |
123 | return ( bool )element; |
124 | case JsonType.number: |
125 | return ( double )element; |
126 | case JsonType.@ string : |
127 | return ( string )element; |
128 | case JsonType.@ object : |
129 | case JsonType.array: |
130 | return new DynJsonHelper(element, type); |
131 | case JsonType.@ null : |
132 | default : |
133 | return null ; |
134 | } |
135 | } |
136 | /// <summary> |
137 | /// 获取Json字段类型 |
138 | /// </summary> |
139 | /// <param name="obj"></param> |
140 | /// <returns></returns> |
141 | private static JsonType GetJsonType( object obj) |
142 | { |
143 | if (obj == null ) return JsonType.@ null ; |
144 |
145 | switch (Type.GetTypeCode(obj.GetType())) |
146 | { |
147 | case TypeCode.Boolean: |
148 | return JsonType.boolean; |
149 | case TypeCode.String: |
150 | case TypeCode.Char: |
151 | case TypeCode.DateTime: |
152 | return JsonType.@ string ; |
153 | case TypeCode.Int16: |
154 | case TypeCode.Int32: |
155 | case TypeCode.Int64: |
156 | case TypeCode.UInt16: |
157 | case TypeCode.UInt32: |
158 | case TypeCode.UInt64: |
159 | case TypeCode.Single: |
160 | case TypeCode.Double: |
161 | case TypeCode.Decimal: |
162 | case TypeCode.SByte: |
163 | case TypeCode.Byte: |
164 | return JsonType.number; |
165 | case TypeCode.Object: |
166 | return (obj is IEnumerable) ? JsonType.array : JsonType.@ object ; |
167 | case TypeCode.DBNull: |
168 | case TypeCode.Empty: |
169 | default : |
170 | return JsonType.@ null ; |
171 | } |
172 | } |
173 |
174 | private static XAttribute CreateTypeAttr(JsonType type) |
175 | { |
176 | return new XAttribute( "type" , type.ToString()); |
177 | } |
178 |
179 | private static object CreateJsonNode( object obj) |
180 | { |
181 | var type = GetJsonType(obj); |
182 | switch (type) |
183 | { |
184 | case JsonType.@ string : |
185 | case JsonType.number: |
186 | return obj; |
187 | case JsonType.boolean: |
188 | return obj.ToString().ToLower(); |
189 | case JsonType.@ object : |
190 | return CreateXObject(obj); |
191 | case JsonType.array: |
192 | return CreateXArray(obj as IEnumerable); |
193 | case JsonType.@ null : |
194 | default : |
195 | return null ; |
196 | } |
197 | } |
198 | private static IEnumerable<XStreamingElement> CreateXArray<T>(T obj) where T : IEnumerable |
199 | { |
200 | return obj.Cast< object >() |
201 | .Select(o => new XStreamingElement( "item" , CreateTypeAttr(GetJsonType(o)), CreateJsonNode(o))); |
202 | } |
203 | private static IEnumerable<XStreamingElement> CreateXObject( object obj) |
204 | { |
205 | return obj.GetType() |
206 | .GetProperties(BindingFlags.Public | BindingFlags.Instance) |
207 | .Select(pi => new { Name = pi.Name, Value = pi.GetValue(obj, null ) }) |
208 | .Select(a => new XStreamingElement(a.Name, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value))); |
209 | } |
210 | private static string CreateJsonString(XStreamingElement element) |
211 | { |
212 | try |
213 | { |
214 | using (var ms = new MemoryStream()) |
215 | using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.Unicode)) |
216 | { |
217 | element.WriteTo(writer); |
218 | writer.Flush(); |
219 | return Encoding.Unicode.GetString(ms.ToArray()); |
220 | } |
221 | } |
222 | catch (Exception exc) { return exc.Message; } |
223 | } |
224 | //动态处理对象和数组List |
225 | readonly XElement xml; |
226 | readonly JsonType jsonType; |
227 | /// <summary> |
228 | /// 创建无参构造函数 |
229 | /// </summary> |
230 | public DynJsonHelper() |
231 | { |
232 | xml = new XElement( "root" , CreateTypeAttr(JsonType.@ object )); |
233 | jsonType = JsonType.@ object ; |
234 | } |
235 | private DynJsonHelper(XElement element, JsonType type) |
236 | { |
237 | Debug.Assert(type == JsonType.array || type == JsonType.@ object ); |
238 | xml = element; |
239 | jsonType = type; |
240 | } |
241 | public bool IsObject { get { return jsonType == JsonType.@ object ; } } |
242 | public bool IsArray { get { return jsonType == JsonType.array; } } |
243 | /// <summary> |
244 | /// 类型属性验证 |
245 | /// </summary> |
246 | /// <param name="name"></param> |
247 | /// <returns></returns> |
248 | public bool IsDefined( string name) |
249 | { |
250 | return IsObject && (xml.Element(name) != null ); |
251 | } |
252 | /// <summary> |
253 | /// 类型属性验证 |
254 | /// </summary> |
255 | /// <param name="index"></param> |
256 | /// <returns></returns> |
257 | public bool IsDefined( int index) |
258 | { |
259 | return IsArray && (xml.Elements().ElementAtOrDefault(index) != null ); |
260 | } |
261 |
262 | /// <summary> |
263 | /// 删除属性 |
264 | /// </summary> |
265 | /// <param name="name"></param> |
266 | /// <returns></returns> |
267 | public bool Delete( string name) |
268 | { |
269 | var elem = xml.Element(name); |
270 | if (elem != null ) |
271 | { |
272 | elem.Remove(); |
273 | return true ; |
274 | } |
275 | else return false ; |
276 | } |
277 |
278 | /// <summary> |
279 | /// 删除属性 |
280 | /// </summary> |
281 | /// <param name="index"></param> |
282 | /// <returns></returns> |
283 | public bool Delete( int index) |
284 | { |
285 | var elem = xml.Elements().ElementAtOrDefault(index); |
286 | if (elem != null ) |
287 | { |
288 | elem.Remove(); |
289 | return true ; |
290 | } |
291 | else return false ; |
292 | } |
293 | /// <summary> |
294 | /// 映射到数组或类的公共属性名 |
295 | /// </summary> |
296 | /// <typeparam name="T"></typeparam> |
297 | /// <returns></returns> |
298 | public T Deserialize<T>() |
299 | { |
300 | return (T)Deserialize( typeof (T)); |
301 | } |
302 | private object Deserialize(Type type) |
303 | { |
304 | return (IsArray) ? DeserializeArray(type) : DeserializeObject(type); |
305 | } |
306 | private dynamic DeserializeValue(XElement element, Type elementType) |
307 | { |
308 | var value = ToValue(element); |
309 | if (value is DynJsonHelper) |
310 | { |
311 | value = ((DynJsonHelper)value).Deserialize(elementType); |
312 | } |
313 | return Convert.ChangeType(value, elementType); |
314 | } |
315 | private object DeserializeObject(Type targetType) |
316 | { |
317 | var result = Activator.CreateInstance(targetType); |
318 | var dict = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) |
319 | .Where(p => p.CanWrite) |
320 | .ToDictionary(pi => pi.Name, pi => pi); |
321 | foreach (var item in xml.Elements()) |
322 | { |
323 | PropertyInfo propertyInfo; |
324 | if (!dict.TryGetValue(item.Name.LocalName, out propertyInfo)) continue ; |
325 | var value = DeserializeValue(item, propertyInfo.PropertyType); |
326 | propertyInfo.SetValue(result, value, null ); |
327 | } |
328 | return result; |
329 | } |
330 | private object DeserializeArray(Type targetType) |
331 | { |
332 | if (targetType.IsArray) // Jsons[]==>数组[] |
333 | { |
334 | var elemType = targetType.GetElementType(); |
335 | dynamic array = Array.CreateInstance(elemType, xml.Elements().Count()); |
336 | var index = 0; |
337 | foreach (var item in xml.Elements()) |
338 | { |
339 | array[index ] = DeserializeValue(item, elemType); |
340 | } |
341 | return array; |
342 | } |
343 | else // Jsons<Foo>==>List |
344 | { |
345 | var elemType = targetType.GetGenericArguments()[0]; |
346 | dynamic list = Activator.CreateInstance(targetType); |
347 | foreach (var item in xml.Elements()) |
348 | { |
349 | list.Add(DeserializeValue(item, elemType)); |
350 | } |
351 | return list; |
352 | } |
353 | } |
354 | /// <summary> |
355 | /// 删除 |
356 | /// </summary> |
357 | /// <param name="binder"></param> |
358 | /// <param name="args"></param> |
359 | /// <param name="result"></param> |
360 | /// <returns></returns> |
361 | public override bool TryInvoke(InvokeBinder binder, object [] args, out object result) |
362 | { |
363 | result = (IsArray) |
364 | ? Delete(( int )args[0]) |
365 | : Delete(( string )args[0]); |
366 | return true ; |
367 | } |
368 | /// <summary> |
369 | /// 重写TryInvokeMember方法 |
370 | /// </summary> |
371 | /// <param name="binder"></param> |
372 | /// <param name="args"></param> |
373 | /// <param name="result"></param> |
374 | /// <returns></returns> |
375 | public override bool TryInvokeMember(InvokeMemberBinder binder, object [] args, out object result) |
376 | { |
377 | if (args.Length > 0) |
378 | { |
379 | result = null ; |
380 | return false ; |
381 | } |
382 | result = IsDefined(binder.Name); |
383 | return true ; |
384 | } |
385 | /// <summary> |
386 | /// 重写TryConvert方法 |
387 | /// Deserialize or foreach(IEnumerable) |
388 | /// </summary> |
389 | /// <param name="binder"></param> |
390 | /// <param name="result"></param> |
391 | /// <returns></returns> |
392 | public override bool TryConvert(ConvertBinder binder, out object result) |
393 | { |
394 | if (binder.Type == typeof (IEnumerable) || binder.Type == typeof ( object [])) |
395 | { |
396 | var ie = (IsArray) |
397 | ? xml.Elements().Select(x => ToValue(x)) |
398 | : xml.Elements().Select(x => (dynamic) new KeyValuePair< string , object >(x.Name.LocalName, ToValue(x))); |
399 | result = (binder.Type == typeof ( object [])) ? ie.ToArray() : ie; |
400 | } |
401 | else |
402 | { |
403 | result = Deserialize(binder.Type); |
404 | } |
405 | return true ; |
406 | } |
407 | private bool TryGet(XElement element, out object result) |
408 | { |
409 | if (element == null ) |
410 | { |
411 | result = null ; |
412 | return false ; |
413 | } |
414 |
415 | result = ToValue(element); |
416 | return true ; |
417 | } |
418 | public override bool TryGetIndex(GetIndexBinder binder, object [] indexes, out object result) |
419 | { |
420 | return (IsArray) |
421 | ? TryGet(xml.Elements().ElementAtOrDefault(( int )indexes[0]), out result) |
422 | : TryGet(xml.Element(( string )indexes[0]), out result); |
423 | } |
424 | public override bool TryGetMember(GetMemberBinder binder, out object result) |
425 | { |
426 | return (IsArray) |
427 | ? TryGet(xml.Elements().ElementAtOrDefault( int .Parse(binder.Name)), out result) |
428 | : TryGet(xml.Element(binder.Name), out result); |
429 | } |
430 | private bool TrySet( string name, object value) |
431 | { |
432 | var type = GetJsonType(value); |
433 | var element = xml.Element(name); |
434 | if (element == null ) |
435 | { |
436 | xml.Add( new XElement(name, CreateTypeAttr(type), CreateJsonNode(value))); |
437 | } |
438 | else |
439 | { |
440 | element.Attribute( "type" ).Value = type.ToString(); |
441 | element.ReplaceNodes(CreateJsonNode(value)); |
442 | } |
443 |
444 | return true ; |
445 | } |
446 | private bool TrySet( int index, object value) |
447 | { |
448 | var type = GetJsonType(value); |
449 | var e = xml.Elements().ElementAtOrDefault(index); |
450 | if (e == null ) |
451 | { |
452 | xml.Add( new XElement( "item" , CreateTypeAttr(type), CreateJsonNode(value))); |
453 | } |
454 | else |
455 | { |
456 | e.Attribute( "type" ).Value = type.ToString(); |
457 | e.ReplaceNodes(CreateJsonNode(value)); |
458 | } |
459 |
460 | return true ; |
461 | } |
462 | public override bool TrySetIndex(SetIndexBinder binder, object [] indexes, object value) |
463 | { |
464 | return (IsArray) |
465 | ? TrySet(( int )indexes[0], value) |
466 | : TrySet(( string )indexes[0], value); |
467 | } |
468 | public override bool TrySetMember(SetMemberBinder binder, object value) |
469 | { |
470 | return (IsArray) |
471 | ? TrySet( int .Parse(binder.Name), value) |
472 | : TrySet(binder.Name, value); |
473 | } |
474 | public override IEnumerable< string > GetDynamicMemberNames() |
475 | { |
476 | return (IsArray) |
477 | ? xml.Elements().Select((x, i) => i.ToString()) |
478 | : xml.Elements().Select(x => x.Name.LocalName); |
479 | } |
480 | /// <summary> |
481 | /// 重写ToString方法 |
482 | /// </summary> |
483 | /// <returns></returns> |
484 | public override string ToString() |
485 | { |
486 | //无法序列化就剔除 |
487 | foreach (var elem in xml.Descendants().Where(x => x.Attribute( "type" ).Value == "null" )) |
488 | { |
489 | elem.RemoveNodes(); |
490 | } |
491 | return CreateJsonString( new XStreamingElement( "root" , CreateTypeAttr(jsonType), xml.Elements())); |
492 | } |
493 | #endregion |
494 |
495 | } |
496 | } |
原文链接:Dynamic动态Json解析帮助类