using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; #if !NET20 using System.Dynamic; using System.IO; #endif using System.Reflection; using static Apewer.NumberUtility; using static Apewer.RuntimeUtility; namespace Apewer { /// Json。 [Serializable] public sealed class Json #if !NET20 : DynamicObject #endif { #region 配置。 [NonSerialized] private static bool _throw = false; [NonSerialized] private static bool _recursively = true; [NonSerialized] private static bool _forceall = true; /// 允许抛出 Exception,默认为不允许。 public static bool AllowException { get { return _throw; } set { _throw = value; } } /// 当存在递归引用时候包含递归项。指定为 True 时递归项为 Null 值,指定为 False 时不包含递归项。默认值:False。 public static bool AllowRecursively { get { return _recursively; } set { _recursively = value; } } /// 将所有类型视为拥有 特性。 /// 默认值:FALSE。 public static bool ForceAll { get => _forceall; set => _forceall = value; } #endregion #region 消息 private const string ValueIsNotSupported = "指定的值类型不受支持"; private const string IsNotJsonObject = "当前实例不是 Json 对象。"; private const string IsNotJsonArray = "当前实例不是 Json 数组。"; private const string InvalidIndex = "未指定有效的索引。"; private const string IndexLessZero = "指定的索引小于 0,无效。"; private const string IndexGraterMax = "指定的索引超出了最大值,无效。"; private const string IndexGraterCount = "指定的索引超出了数量,无效。"; #endregion #region JToken [NonSerialized] private JToken _jtoken = null; [NonSerialized] private JArray _jarray = null; [NonSerialized] private JObject _jobject = null; [NonSerialized] private JProperty _jproperty = null; [NonSerialized] private JValue _jvalue = null; static JToken ToJToken(object value) { if (value == null) return new JValue(null, JTokenType.Null); var type = value.GetType(); if (RuntimeUtility.IsNullableType(type)) value = RuntimeUtility.GetNullableValue(value); if (value == null) return new JValue(null, JTokenType.Null); if (value is Json json) return json?._jtoken ?? new JValue(null, JTokenType.Null); if (value is DateTime dt) return new JValue(SerializeDateTime(dt)); if (value is string) return new JValue(value); if (value is bool) return new JValue(value); if (value is byte) return new JValue(value); if (value is sbyte) return new JValue(value); if (value is short) return new JValue(value); if (value is ushort) return new JValue(value); if (value is int) return new JValue(value); if (value is uint) return new JValue(value); if (value is long) return new JValue(value); if (value is ulong uint64) return (uint64 > int.MaxValue) ? new JValue(uint64.ToString()) : new JValue(Convert.ToInt64(uint64)); if (value is float) return new JValue(value); if (value is double) return new JValue(value); if (value is decimal) return new JValue(value); var from = From(value); if (from != null) return from._jtoken; throw new ArgumentException(ValueIsNotSupported); } static object ParseJToken(JToken jtoken) { if (jtoken == null) return null; if (jtoken is JValue jvalue) return jvalue.Value; if (jtoken is JObject) return new Json(jtoken); if (jtoken is JArray) return new Json(jtoken); if (jtoken is JProperty jproperty) { var value = jproperty.Value; if (value == null) return null; return ParseJToken(value); } throw new InvalidOperationException($"Json 类型 {jtoken.Type} 不支持解析。"); } #endregion #region 构造。 #region Reset /// 重置当前对象为空。 public void Reset() { Construct(); } /// 使用指定的文本重置当前对象。 public bool Reset(string json) { Construct(); if (json == null) { if (AllowException) throw new ArgumentNullException("json", "参数无效。"); return false; } var parsed = From(json); if (parsed == null) return false; Construct(parsed._jtoken); return true; } /// 使用指定的对象重置当前对象。 /// /// public bool Reset(Json json) { Construct(); if (json == null) { if (AllowException) throw new ArgumentNullException("json", "参数无效。"); return false; } var parsed = From(json.ToString()); if (parsed == null) return false; Construct(parsed._jtoken); return true; } /// 使用指定的字典对象重置当前对象。 /// /// public bool Reset(Dictionary dictionary) { Construct(); if (dictionary == null) { if (AllowException) throw new ArgumentNullException("dictionary", "参数无效。"); return false; } var json = NewObject(); foreach (var item in dictionary) json[item.Key] = item.Value; Construct(json._jtoken); return true; } /// 使用指定的文本字典对象重置当前对象。 /// /// public bool Reset(TextSet dictionary) { Construct(); if (dictionary == null) { if (AllowException) throw new ArgumentNullException("dictionary", "参数无效。"); return false; } return Reset(dictionary.Origin); } /// 使用指定的文本字典对象重置当前对象。 /// /// public bool Reset(ObjectSet dictionary) { Construct(); if (dictionary == null) { if (AllowException) throw new ArgumentNullException("dictionary", "参数无效。"); return false; } return Reset(dictionary.Origin); } #endregion private void Construct(JToken jtoken = null) { _jtoken = jtoken; _jarray = null; _jobject = null; _jproperty = null; _jvalue = null; if (_jtoken != null) { if (_jtoken is JArray) _jarray = (JArray)_jtoken; if (_jtoken is JObject) _jobject = (JObject)_jtoken; if (_jtoken is JProperty) _jproperty = (JProperty)_jtoken; if (_jtoken is JValue) _jvalue = (JValue)_jtoken; } } private Json(JToken jtoken) { Construct(jtoken); } /// 创建 Json Object 实例。 public Json() { Construct(new JObject()); } #endregion #region 属性。 /// 用于兼容 SimpleJson 的操作。 public string this[string name] { get => GetProperty(name)?.ToString() ?? ""; set => SetProperty(name, value ?? ""); } /// 获取或设置数组的元素。 public object this[int index] { get => GetItem(index); set => SetItem(index, value); } private JTokenType TokenType { get { if (_jtoken == null) return JTokenType.None; else return _jtoken.Type; //if (_jtoken == null) return 0; //switch (_jtoken.Type) //{ // case JTokenType.None: return 0; // case JTokenType.Object: return 1; // case JTokenType.Array: return 2; // case JTokenType.Constructor: return 3; // case JTokenType.Property: return 4; // case JTokenType.Comment: return 5; // case JTokenType.Integer: return 6; // case JTokenType.Float: return 7; // case JTokenType.String: return 8; // case JTokenType.Boolean: return 9; // case JTokenType.Null: return 10; // case JTokenType.Undefined: return 11; // case JTokenType.Date: return 12; // case JTokenType.Raw: return 13; // case JTokenType.Bytes: return 14; // case JTokenType.Guid: return 15; // case JTokenType.Uri: return 16; // case JTokenType.TimeSpan: return 17; // default: return 0; //} } } /// /// 获取当前实例的类型。可能的类型: /// None Object Array Constructor Property Comment Integer Float String /// Boolean Null Undefined Date Raw Bytes Guid Uri TimeSpan /// public string Type { get { return TokenType.ToString(); } } /// 实例有效。 public bool Available { get { return _jtoken != null && TokenType != JTokenType.None; } } /// 获取当前实例的值,当为 Json 格式时缩进。 public string Lucid { get { return ToString(true); } } /// 获取当前实例的值,当为 Json 格式时不缩进。 public string Text { get { return ToString(false); } } /// 当前实例类型为 Property 时,获取名称。 public string Name { get { return _jproperty == null ? null : _jproperty.Name; } } /// 获取值。 public object Value { get { if (_jvalue != null) { if (_jvalue.Value == null) return null; if (_jvalue.Value is JValue jvalue) return jvalue.Value; if (_jvalue.Value is JToken jtoken) return new Json(jtoken); else return _jvalue.Value; } if (_jproperty != null) { if (_jproperty.Value == null) return null; if (_jproperty.Value is JValue jvalue) return jvalue.Value; if (_jproperty.Value is JToken jtoken) return new Json(jtoken); else return _jproperty.Value; } return null; } } /// 实例无效。 public bool IsNull { get { return _jtoken == null; } } #endregion #region Private Get private Json[] PrivateGetProperties { get { return GetProperties(); } } private Json[] PrivateGetValues { get { return GetValues(); } } private Json[] PrivateGetObjects { get { return GetObjects(); } } private Json[] PrivateGetItems { get { return GetItems(); } } #endregion #region Object : Get/Set /// 获取所有类型为 Property 的子项。 public Json[] GetProperties() { var ab = new ArrayBuilder(); if (_jobject != null) { var children = _jobject.Children(); foreach (var child in children) { var json = new Json(child); ab.Add(json); } } return ab.Export(); } /// 当前实例类型为 Object 时搜索属性,失败时返回 Null。 /// 将要搜索的属性名称,不可为 Null。 /// /// public Json GetProperty(string name) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return null; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return null; } var children = _jtoken.Children(); foreach (var child in children) { if (child.Name == name) { var json = new Json(child.Value); return json; } } return null; } /// 当前实例类型为 Object 时添加属性,值为 Null,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// /// public bool SetProperty(string name) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, null); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性。 /// /// /// public bool SetProperty(Json property) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (property == null) { if (_throw) throw new ArgumentNullException("property", "参数无效。"); return false; } if (property._jproperty == null || property.TokenType != JTokenType.Property) { if (_throw) throw new ArgumentException("property", "将要设置的属性无效。"); return false; } var name = property._jproperty.Name; var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, property._jtoken); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, bool value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, string value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, int value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, long value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, float value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, double value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// public bool SetProperty(string name, decimal value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } _jobject.Add(name, value); return true; } /// 当前实例类型为 Object 时添加属性,已存在的属性将被替换。 /// 将要添加的属性名称,不可为 Null。 /// 将要添加的属性值。 /// /// /// public bool SetProperty(string name, Json value) { if (_jobject == null || TokenType != JTokenType.Object) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (name == null) { if (_throw) throw new ArgumentNullException("name", "参数无效。"); return false; } var children = _jobject.Children(); foreach (var child in children) { if (child.Name == name) { _jobject.Remove(name); break; } } if (value == null) { _jobject.Add(name, null); } else { if (value._jtoken == null) { _jobject.Add(name, null); } else { _jobject.Add(name, value._jtoken); } } return true; } #endregion #region Array /// 获取所有类型为 Value 的子项。 public Json[] GetValues() { var ab = new ArrayBuilder(); if (_jarray != null) { var children = _jarray.Children(); foreach (var child in children) { var json = new Json(child); ab.Add(json); } } return ab.Export(); } /// 获取所有类型为 Object 的子项。 public Json[] GetObjects() { var ab = new ArrayBuilder(); if (_jarray != null) { var children = _jarray.Children(); foreach (var child in children) { var json = new Json(child); ab.Add(json); } } return ab.Export(); } /// 获取 Array 中的所有元素。 public Json[] GetItems() { var ab = new ArrayBuilder(); if (_jarray != null) { var children = _jarray.Children(); foreach (var child in children) { var json = new Json(child); ab.Add(json); } } return ab.Export(); } /// 当前实例类型为 Array 时添加 Null 元素。 /// public bool AddItem() { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(JValue.CreateNull()); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(Json json) { if (json == null) { return AddItem(); } if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } if (json._jtoken == null || json.TokenType == JTokenType.None) { if (_throw) throw new ArgumentException("json", "将要设置的元素无效。"); return false; } _jarray.Add(json._jtoken); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(string value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value ?? ""); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(bool value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(int value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(long value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(float value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(double value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 当前实例类型为 Array 时添加元素。 /// 将要添加的元素。 /// public bool AddItem(decimal value) { if (_jarray == null || TokenType != JTokenType.Array) { if (_throw) throw new InvalidOperationException("当前实例不支持元素。"); return false; } _jarray.Add(value); return true; } /// 从 Parent 中移除。 /// /// public bool Remove() { if (_jtoken == null) return false; if (_jtoken.Parent == null) { if (_throw) throw new InvalidOperationException("Parent 对象丢失。"); return false; } try { _jtoken.Remove(); return true; } catch (Exception exception) { if (_throw) throw exception; return false; } } /// 获取数组的元素。 /// /// public object GetItem(int index) { if (!IsArray) throw new InvalidOperationException(IsNotJsonArray); if (index < 0) throw new ArgumentOutOfRangeException(nameof(index), IndexLessZero); var jarray = _jtoken as JArray; if (index >= jarray.Count) throw new ArgumentOutOfRangeException(nameof(index), IndexGraterCount); var item = jarray[index]; return ParseJToken(item); } /// 设置数组的元素。 /// /// /// public void SetItem(int index, object value) { if (!IsArray) throw new InvalidOperationException(IsNotJsonArray); if (index < 0) throw new ArgumentOutOfRangeException(nameof(index), IndexLessZero); var jarray = _jtoken as JArray; while (jarray.Count < index + 1) jarray.Add(null); var jtoken = ToJToken(value); jarray.SetItem(index, jtoken); } #endregion #region Property /// Json 对象实例为空。 public bool IsNone { get { return TokenType == JTokenType.None; } } /// Json 对象为 Object 实例。 public bool IsObject { get { return TokenType == JTokenType.Object; } } /// Json 对象为 Array 实例。 public bool IsArray { get { return TokenType == JTokenType.Array; } } /// Json 对象为 Property 实例。 public bool IsProperty { get { return TokenType == JTokenType.Property; } } /// Json 对象为 String 实例。 public bool IsString { get { return TokenType == JTokenType.String; } } /// 当前实例类型为 Property 时设置 Null 值。 /// public bool SetValue() { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = JValue.CreateNull(); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(Json value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } if (value == null) { _jproperty.Value = JValue.CreateNull(); return true; } if (value._jtoken == null || value.TokenType == JTokenType.None) { _jproperty.Value = JValue.CreateNull(); return true; } _jproperty.Value = new JValue(value._jtoken); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(string value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = value == null ? JValue.CreateNull() : JValue.CreateString(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(bool value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(int value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(long value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(float value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(double value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } /// 当前实例类型为 Property 时设置值。 /// 将要设置的值。 /// public bool SetValue(decimal value) { var available = _jproperty != null && TokenType == JTokenType.Property; if (!available) { if (_throw) throw new InvalidOperationException("当前实例不支持属性。"); return false; } _jproperty.Value = new JValue(value); return true; } #endregion #region Import / Export #region String -> Json /// 解析文本为 Json 对象,失败时返回 Null。 /// public static Json From(string text) { try { var jtoken = JToken.Parse(text); var json = new Json(jtoken); return json; } catch (Exception exception) { if (AllowException) throw exception; return null; } } #endregion #region Object -> Json /// 解析实现 IList 的对象为 Json 对象,失败时返回 Null。 /// 将要解析的对象。 /// 在 Json 中将属性名称转换为小写。 /// 限制 Json 层级深度,当值小于零时将不限制深度。 /// 强制解析属性,忽略 Serializable 特性。 public static Json From(IList entity, bool lower = false, int depth = -1, bool force = false) { if (entity == null) return null; var recursive = new object[] { entity }; return From(entity, lower, recursive, depth, force); } /// 解析实现 IDictionary 的对象为 Json 对象,失败时返回 Null。 /// 将要解析的对象。 /// 在 Json 中将属性名称转换为小写。 /// 限制 Json 层级深度,当值小于零时将不限制深度。 /// 强制解析属性,忽略 Serializable 特性。 public static Json From(IDictionary entity, bool lower = false, int depth = -1, bool force = false) { if (entity == null) return null; var recursive = new object[] { entity }; return From(entity, lower, recursive, depth, force); } /// /// 解析对象为 Json 对象,包含所有公共属性,失败时返回 Null。 /// String 对象将解析文本;Json 对象将返回实例;String 对象将解析文本;实现 IDictionary 或 IList 的对象将解析内容。 /// /// 将要解析的对象。 /// 在 Json 中将属性名称转换为小写。 /// 限制 Json 层级深度,当值小于零时将不限制深度。 /// 强制解析属性,忽略 Serializable 特性。 /// public static Json From(object entity, bool lower = false, int depth = -1, bool force = false) { if (entity == null) return null; var recursive = new object[] { entity }; return From(entity, lower, recursive, depth, force); } private static Json From(IList list, bool lower, object[] previous, int depth, bool force) { if (list == null) return null; if (list is IToJson) return ((IToJson)list).ToJson(); var checker = list as IToJsonChecker; var json = NewArray(); try { if (list is Array array) { if (array != null && array.Rank > 1) { ToJson(json, array, array.Rank, new int[0]); return json; } } foreach (var item in list) { // 由 IToJsonChecker 实现的方法检查是否包含元素。 if (checker != null && !checker.WithItemInJson(list, item)) continue; var value = item; // 检查递归引用。 var recursively = false; foreach (var r in previous) { if (ReferenceEquals(r, value)) { if (AllowRecursively) json.AddItem(); recursively = true; break; } } if (recursively) continue; // value 是 null。 if (value.IsNull()) { json.AddItem(); continue; } // 处理 Type 对象。 if (value.GetType().Equals(typeof(Type)) && (previous.Length > 2)) value = FullName((Type)value); // 处理 Assembly 对象。 if (value.GetType().Equals(typeof(Assembly)) && (previous.Length > 2)) value = ((Assembly)value).FullName; if (value == null) { json.AddItem(); } else if (value is DateTime dt) { json.AddItem(SerializeDateTime(dt)); } else if (value is bool) { json.AddItem((bool)value); } else if (value is byte) { json.AddItem((byte)value); } else if (value is sbyte) { json.AddItem((sbyte)value); } else if (value is short) { json.AddItem((short)value); } else if (value is ushort) { json.AddItem((ushort)value); } else if (value is int) { json.AddItem((int)value); } else if (value is uint) { json.AddItem((uint)value); } else if (value is long) { json.AddItem((long)value); } else if (value is ulong) { json.AddItem(value.ToString()); } else if (value is float) { json.AddItem((float)value); } else if (value is double) { json.AddItem((double)value); } else if (value is decimal) { json.AddItem((decimal)value); } else if (value is string) { json.AddItem((string)value); } else if (value is Json) { json.AddItem(value as Json); } else { if ((depth < 0) || (0 < depth && previous.Length < depth)) { var recursive = new ArrayBuilder(16); recursive.Add(previous); recursive.Add(value); if (value is IDictionary asExpando) { var expando = new Dictionary(asExpando); json.AddItem(From(expando, lower, recursive, depth, force)); } else if (value is IDictionary) { json.AddItem(From(value as IDictionary, lower, recursive, depth, force)); } else if (value is IList) { json.AddItem(From(value as IList, lower, recursive, depth, force)); } else { json.AddItem(From(value, lower, recursive, depth, force)); } } else { json.AddItem(value.ToString()); } } } } catch { } return json; } private static Json From(IDictionary dictionary, bool lower, object[] previous, int depth, bool force) { if (dictionary == null) return null; if (dictionary is IToJson) return ((IToJson)dictionary).ToJson(); // IDictionary 不再需要 SerializableAttribute 特性。 // { // var dtype = dictionary.GetType(); // var sas = dtype.GetCustomAttributes(typeof(SerializableAttribute), false); // if (sas == null || sas.Length < 1) return null; // } var checker = dictionary as IToJsonChecker; var json = NewObject(); try { var keys = dictionary.Keys; foreach (var key in keys) { if (key == null) continue; try { var field = key.ToString() ?? ""; if (lower && !string.IsNullOrEmpty(field)) field = field.ToLower(); var value = dictionary[key]; // 检查递归引用。 var recursively = false; foreach (var r in previous) { if (ReferenceEquals(r, value)) { if (AllowRecursively) json.SetProperty(field); recursively = true; break; } } if (recursively) continue; // 检查 System.Attribute.TypeId。 if (field == "TypeId" || field == "typeid") { if ((value != null) && (value is Type)) { json.SetProperty(field, FullName((Type)value)); continue; } } // 由 IToJsonChecker 实现的方法检查是否包含元素。 if (checker != null && !checker.WithPropertyInJson(dictionary, field, value)) continue; if (value != null) { // 处理 Type 对象。 if (value.GetType().Equals(typeof(Type)) && (previous.Length > 2)) { value = FullName((Type)value); } // 处理 Assembly 对象。 if (value.GetType().Equals(typeof(Assembly)) && (previous.Length > 2)) { value = ((Assembly)value).FullName; } } if (value == null) { json.SetProperty(field); } else if (value is DateTime dt) { json.SetProperty(field, SerializeDateTime(dt)); } else if (value is bool) { json.SetProperty(field, (bool)value); } else if (value is byte) { json.SetProperty(field, (byte)value); } else if (value is sbyte) { json.SetProperty(field, (sbyte)value); } else if (value is short) { json.SetProperty(field, (short)value); } else if (value is ushort) { json.SetProperty(field, (ushort)value); } else if (value is int) { json.SetProperty(field, (int)value); } else if (value is uint) { json.SetProperty(field, (uint)value); } else if (value is long) { json.SetProperty(field, (long)value); } else if (value is ulong) { json.SetProperty(field, value.ToString()); } else if (value is float) { json.SetProperty(field, (float)value); } else if (value is double) { json.SetProperty(field, (double)value); } else if (value is decimal) { json.SetProperty(field, (decimal)value); } else if (value is string) { json.SetProperty(field, (string)value); } else if (value is Json) { json.SetProperty(field, value as Json); } else { if ((depth < 0) || (0 < depth && previous.Length < depth)) { var recursive = new ArrayBuilder(16); recursive.Add(previous); recursive.Add(value); if (value is IDictionary) { json.SetProperty(field, From(value as IDictionary, lower, recursive, depth, force)); } else if (value is IList) { json.SetProperty(field, From(value as IList, lower, recursive, depth, force)); } else { json.SetProperty(field, From(value, lower, recursive, depth, force)); } } else { json.SetProperty(field, value.ToString()); } } } catch { } } } catch { } return json; } private static Json From(object entity, bool lower, object[] previous, int depth, bool force) { if (entity == null) return null; if (entity is IToJson) return ((IToJson)entity).ToJson(); if (entity is string) return From(entity as string); // 递归检查。 var pab = new ArrayBuilder(16); if (previous != null) pab.Add(previous as IEnumerable); pab.Add(entity); var end = depth > 0 && pab.Count >= depth; // 不可递归类型:类型。 if (entity is Type) { var t = entity as Type; if (t.Equals(typeof(void))) return null; var tJson = NewObject(); if (end) tJson.SetProperty(lower ? "name" : "Name", FullName(t)); else { tJson.SetProperty(lower ? "name" : "Name", t.Name); if (t.IsGenericType) { tJson.SetProperty(lower ? "generic" : "Generic", From(t.GetGenericArguments(), lower, pab, 2, true)); } tJson.SetProperty(lower ? "namespace" : "Namespace", t.Namespace); } tJson.SetProperty(lower ? "assembly" : "Assembly", t.Assembly.Location); if (end) { tJson.SetProperty(lower ? "properties" : "Properties", t.GetProperties().Length); tJson.SetProperty(lower ? "methods" : "Methods", t.GetMethods().Length); } else { tJson.SetProperty(lower ? "properties" : "Properties", From(t.GetProperties(), lower, new object[0], 1, true)); tJson.SetProperty(lower ? "methods" : "Methods", From(t.GetMethods(), lower, new object[0], 1, true)); } return tJson; } // 不可递归类型:方法。 if (entity is MethodBase) { var mb = entity as MethodBase; var mbJson = NewObject(); mbJson.SetProperty(lower ? "name" : "Name", mb.Name); mbJson.SetProperty(lower ? "declaring" : "Declaring", FullName(mb.DeclaringType)); if (mb.IsStatic) mbJson.SetProperty(lower ? "static" : "Static", mb.IsStatic); if (mb is MethodInfo mi) { mbJson.SetProperty(lower ? "type" : "Type", FullName(mi.ReturnType)); } mbJson.SetProperty(lower ? "parameters" : "Parameters", mb.GetParameters().Length); return mbJson; } // 不可递归类型:成员。 if (entity is MemberInfo) { var mi = entity as MemberInfo; var miJson = NewObject(); miJson.SetProperty(lower ? "name" : "Name", mi.Name); miJson.SetProperty(lower ? "declaring" : "Declaring", FullName(mi.DeclaringType)); miJson.SetProperty(lower ? "type" : "Type", mi.MemberType.ToString()); if (mi is PropertyInfo pi) { var getter = pi.GetGetMethod(); var setter = pi.GetSetMethod(); var isStatic = (getter != null && getter.IsStatic) || (setter != null && setter.IsStatic); if (isStatic) miJson.SetProperty(lower ? "static" : "Static", isStatic); miJson.SetProperty(lower ? "get" : "Get", getter != null); miJson.SetProperty(lower ? "set" : "Set", setter != null); } else if (mi is FieldInfo fi) { if (fi.IsStatic) miJson.SetProperty(lower ? "static" : "Static", true); } return miJson; } // 不可递归类型:参数。 if (entity is ParameterInfo) { var pi = entity as ParameterInfo; var piJson = NewObject(); piJson.SetProperty(lower ? "name" : "Name", pi.Name); piJson.SetProperty(lower ? "type" : "Type", FullName(pi.ParameterType)); return piJson; } // 强制序列化。 var exception = entity as Exception; if (exception != null) force = true; if (!(force || _forceall) && !CanSerialize(entity.GetType(), false)) return null; if (entity is Json) { if (lower) Lower(entity as Json); return entity as Json; } else if (entity is String) { return From((string)entity); } else if (entity is IDictionary asExpando) { return From(new Dictionary(asExpando), lower, depth, force); } else if (entity is IDictionary) { return From(entity as IDictionary, lower, depth, force); } else if (entity is IList) { return From(entity as IList, lower, depth, force); } else if (entity is NameValueCollection nc) { return From(CollectionUtility.Dictionary(nc), lower, depth, force); } var type = entity.GetType(); var independent = RuntimeUtility.Contains(type); var checker = entity as IToJsonChecker; var properties = type.GetProperties(); if (properties.LongLength > 0L) { var dict = new Dictionary(); // 添加异常类型,并提前加入基类属性。 if (exception != null) { dict.Add(lower ? "type" : "Type", FullName(exception.GetType())); dict.Add(lower ? "message" : "Message", Message(exception)); var exData = exception.Data; if (exData != null && exData.Count > 0) dict.Add(lower ? "data" : "Data", exData); var exHelpLink = exception.HelpLink; if (!string.IsNullOrEmpty(exHelpLink)) dict.Add(lower ? "help" : "Help", exHelpLink); if (!end) { var stackJson = NewArray(); var stackJsonLength = 0; var stackText = exception.StackTrace; if (!string.IsNullOrEmpty(stackText)) { var stackSplit = exception.StackTrace.Split('\r', '\n'); foreach (var stackItem in stackSplit) { if (string.IsNullOrEmpty(stackItem)) continue; var stackTrim = stackItem.Trim(); if (string.IsNullOrEmpty(stackTrim)) continue; stackJson.AddItem(stackTrim); stackJsonLength += 1; } } if (stackJsonLength > 0) dict.Add(lower ? "stack" : "Stack", stackJson); var exTargetSite = exception.TargetSite; if (exTargetSite != null) dict.Add(lower ? "target" : "Target", From(exTargetSite, lower, pab, depth, true)); } var innerEx = exception.InnerException; if (innerEx != null) { if (end) dict.Add(lower ? "inner" : "InnerException", FullName(innerEx.GetType())); else dict.Add(lower ? "inner" : "InnerException", From(innerEx, lower, pab, depth, true)); } } foreach (var property in properties) { var field = property.Name; if (field == null) continue; // 有 Independent 的对象不包含继承属性。 if (independent) { if (!property.DeclaringType.Equals(type)) continue; } // 异常不包含基类中的属性。 if (exception != null) { if (property.DeclaringType.Equals(typeof(Exception))) continue; } // 处理 Assembly 对象的 DefinedTypes 和 ExportedTypes 属性。 if (entity is Assembly) { var assembly = entity as Assembly; if (assembly != null) { if (field == "DefinedTypes" || field == "ExportedTypes") { continue; } } } var getter = property.GetGetMethod(false); if (getter == null) continue; if (getter.IsStatic) continue; var value = null as object; try { value = getter.Invoke((object)entity, null); // 由 IToJsonChecker 实现的方法检查是否包含元素。 if (checker != null && !checker.WithPropertyInJson(entity, property, value)) continue; // 处理 Type 对象。 if (getter.ReturnType.Equals(typeof(Type)) && (previous.Length > 2)) { value = FullName((Type)value); } // 处理 Assembly 对象。 if (getter.ReturnType.Equals(typeof(Assembly)) && (previous.Length > 2)) { value = ((Assembly)value).FullName; } } catch (Exception ex) { value = ex.Message; } if (!dict.ContainsKey(field)) dict.Add(field, value); } var json = From(dict, lower, previous, depth, force); return json; } else { return NewObject(); } } private static void ToJson(Json parent, Array array, int rank, int[] indices) { var dimension = indices.Length; var subIndices = new int[dimension + 1]; if (dimension > 0) indices.CopyTo(subIndices, 0); var subLength = array.GetLength(dimension); var end = dimension + 1 >= rank; if (end) { var subLinear = new object[subLength]; for (var i = 0; i < subLength; i++) { subIndices[dimension] = i; subLinear[i] = array.GetValue(subIndices); } var subJson = Json.From(subLinear); parent.Reset(subJson); } else { for (var i = 0; i < subLength; i++) { subIndices[dimension] = i; var subJson = Json.NewArray(); ToJson(subJson, array, rank, subIndices); parent.AddItem(subJson); } } } #endregion #region Json -> String /// 导出文本,可指定缩进。若类型为 String,则导出 String 值,忽略缩进。 internal static string Export(Json json, bool indented) { if (json == null) return ""; if (json._jtoken == null) return ""; if (json.TokenType == JTokenType.String && json._jvalue != null) { return json._jvalue.Value.ToString(); } return json._jtoken.ToString(indented ? Formatting.Indented : Formatting.None); } /// 生成字符串,默认不缩进。若类型为 String,则导出 String 值。 public override string ToString() => Export(this, false); /// 生成字符串,可指定缩进。若类型为 String,则导出 String 值,忽略缩进。 public string ToString(bool indented) => Export(this, indented); #endregion #region Json -> Object /// 填充类型实例,失败时返回 NULL 值。 internal static T Object(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) where T : class, new() { if (json == null) return null; if (json._jtoken == null) return null; if (json.TokenType != JTokenType.Object) return null; var entity = Object(typeof(T), json, ignoreCase, ignoreCharacters, force); return entity == null ? default : (T)entity; } /// 将 Json 填充到数组列表,失败时返回 NULL 值。 internal static TItem[] Array(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) { if (json == null) return null; if (json._jtoken == null) return null; if (json.TokenType != JTokenType.Array) return null; var instance = Array(typeof(TItem), json, ignoreCase, ignoreCharacters, force); var array = (TItem[])instance; return array; } static ConstructorInfo GetDeserializeConstructor(Type type) { var types = new Type[] { typeof(Json) }; var independent = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, types, null); if (independent == null) independent = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); return independent; } /// 创建指定类型的新实例,将 Json 的内容填充到新实例中。 public static object Object(Type type, Json json, bool ignoreCase, string ignoreCharacters, bool force) { // 检查参数。 if (type == null) throw new ArgumentNullException(nameof(type)); if (json == null || json._jtoken == null) return null; // 类型自己实现反序列化。 var independent = GetDeserializeConstructor(type); if (independent != null) return independent.Invoke(new object[] { json }); // 是数组。 if (type.IsArray) { var itemType = GetTypeOfArrayItem(type); return Array(itemType, json, ignoreCase, ignoreCharacters, force); } // 是列表 if (typeof(IList).IsAssignableFrom(type)) { var genericTypes = type.GetGenericArguments(); if (genericTypes != null && genericTypes.Length == 1) { var genericType = genericTypes[0]; if (genericType != null) { var array = Array(genericType, json, ignoreCase, ignoreCharacters, force); var list = ArrayToList(array, type); return list; } } } // 必须是有效的 Json 实例。 if (json.TokenType != JTokenType.Object && json.TokenType != JTokenType.Array) return null; // 必须有无参数的构造函数。 var constructor = type.GetConstructor(System.Type.EmptyTypes); if (constructor == null) return null; // 创建实例。 var entity = constructor.Invoke(null); var jps = json.GetProperties(); if (jps.Length < 1) return entity; var etype = entity.GetType(); var eps = etype.GetProperties(); if (eps.Length < 1) return entity; foreach (var ep in eps) { foreach (var jp in jps) { var jpn = TextUtility.Trim(jp.Name); var epn = TextUtility.Trim(ep.Name); if (ignoreCharacters != null) { var characters = ignoreCharacters.ToCharArray(); foreach (var character in characters) { jpn.Replace(character.ToString(), ""); epn.Replace(character.ToString(), ""); } } if (ignoreCase) { if (jpn.Length > 0) jpn = jpn.ToLower(); if (epn.Length > 0) epn = epn.ToLower(); } if (jpn.Length < 1 || epn.Length < 1) continue; if (jpn != epn) continue; var value = jp.Value; if (value == null) continue; Property(entity, ep, value, ignoreCase, ignoreCharacters, force); } } return entity; } static void Add(object entity, object item, int index) { try { if (entity is Array array) array.SetValue(item, index); else if (entity is IList list) list.Add(item); } catch (Exception ex) { if (_throw) throw ex; } } /// internal static object Array(Type itemType, Json json, bool ignoreCase, string ignoreCharacters, bool force) { if (itemType == null) throw new ArgumentNullException(nameof(itemType)); if (json == null) return null; // 必须是有效的 Json 实例。 if (json.TokenType != JTokenType.Array) return null; // 加入列表。 var items = json.GetItems(); var list = new List(items.Length); for (var index = 0; index < items.Length; index++) { var item = items[index]; if (item == null) list.Add(null); else if (itemType.Equals(typeof(Json))) list.Add(item); else if (itemType.Equals(typeof(string))) list.Add(item ? item.Text : null); else if (itemType.Equals(typeof(byte))) list.Add(Byte(item.Text)); else if (itemType.Equals(typeof(short))) list.Add(Int16(item.Text)); else if (itemType.Equals(typeof(int))) list.Add(Int32(item.Text)); else if (itemType.Equals(typeof(long))) list.Add(Int64(item.Text)); else if (itemType.Equals(typeof(sbyte))) list.Add(SByte(item.Text)); else if (itemType.Equals(typeof(ushort))) list.Add(UInt16(item.Text)); else if (itemType.Equals(typeof(uint))) list.Add(UInt32(item.Text)); else if (itemType.Equals(typeof(ulong))) list.Add(UInt64(item.Text)); else if (itemType.Equals(typeof(float))) list.Add(Single(item.Text)); else if (itemType.Equals(typeof(double))) list.Add(Double(item.Text)); else if (itemType.Equals(typeof(decimal))) list.Add(Decimal(item.Text)); else { var serializable = (force || _forceall) ? true : CanSerialize(itemType, false); if (serializable) { var itemInstance = Object(itemType, item, ignoreCase, ignoreCharacters, force); list.Add(itemInstance); } else { list.Add(null); } } } // 输出数组。 var array = System.Array.CreateInstance(itemType, list.Count); for (var i = 0; i < list.Count; i++) array.SetValue(list[i], i); return array; } private static void Property(object entity, PropertyInfo property, object value, bool ignoreCase, string ignoreCharacters, bool force) { if (entity == null) return; if (property == null) return; if (value == null) return; var setter = property.GetSetMethod(); if (setter == null) return; var pt = property.PropertyType; var ptname = FullName(property.PropertyType); if (ptname == FullName(typeof(Json))) { if (value is Json) setter.Invoke(entity, new object[] { value }); } else { if (pt.Equals(typeof(DateTime))) { if (AllowException) { setter.Invoke(entity, new object[] { DeserializeDateTime(value) }); } else { try { setter.Invoke(entity, new object[] { DeserializeDateTime(value) }); } catch { } } } else if (pt.Equals(typeof(string))) { if (value is Json asJson) setter.Invoke(entity, new object[] { ((Json)value).TokenType == JTokenType.Null ? null : ((Json)value).Text }); else setter.Invoke(entity, new object[] { value.ToString() }); } else if (pt.Equals(typeof(bool))) setter.Invoke(entity, new object[] { Boolean(value) }); else if (pt.Equals(typeof(byte))) setter.Invoke(entity, new object[] { Byte(value) }); else if (pt.Equals(typeof(sbyte))) setter.Invoke(entity, new object[] { SByte(value) }); else if (pt.Equals(typeof(short))) setter.Invoke(entity, new object[] { Int16(value) }); else if (pt.Equals(typeof(ushort))) setter.Invoke(entity, new object[] { UInt16(value) }); else if (pt.Equals(typeof(int))) setter.Invoke(entity, new object[] { Int32(value) }); else if (pt.Equals(typeof(uint))) setter.Invoke(entity, new object[] { UInt32(value) }); else if (pt.Equals(typeof(long))) setter.Invoke(entity, new object[] { Int64(value) }); else if (pt.Equals(typeof(ulong))) setter.Invoke(entity, new object[] { UInt64(value) }); else if (pt.Equals(typeof(float))) setter.Invoke(entity, new object[] { Float(value) }); else if (pt.Equals(typeof(double))) setter.Invoke(entity, new object[] { Double(value) }); else if (pt.Equals(typeof(decimal))) setter.Invoke(entity, new object[] { Decimal(value) }); else { var serializable = (force || _forceall); if (!serializable) serializable = CanSerialize(property.PropertyType, false); if (serializable && value is Json json) { if (pt.IsArray) { var array = Array(pt.GetElementType(), json, ignoreCase, ignoreCharacters, force); setter.Invoke(entity, array); } else if (typeof(IList).IsAssignableFrom(pt)) { var genericTypes = pt.GetGenericArguments(); if (genericTypes != null && genericTypes.Length == 1) { var genericType = genericTypes[0]; if (genericType != null) { var array = Array(genericType, json, ignoreCase, ignoreCharacters, force); var list = ArrayToList(array, pt); setter.Invoke(entity, list); } } } else { var @object = Object(pt, json, ignoreCase, ignoreCharacters, force); setter.Invoke(entity, @object); } } } } } static IList ArrayToList(object array, Type listType) { if (listType == null) throw new ArgumentNullException(nameof(listType)); if (array != null && array is Array a) { var list = Activator.CreateInstance(listType) as IList; for (var i = 0; i < a.Length; i++) list.Add(a.GetValue(i)); return list; } return null; } #endregion #endregion #region Dynamic #if !NET20 /// public override bool TryGetMember(GetMemberBinder binder, out object result) { if (!IsObject) throw new InvalidOperationException(IsNotJsonObject); var contains = _jobject.ContainsKey(binder.Name); if (!contains) { result = null; return true; } var jtoken = _jobject.GetValue(binder.Name); result = ParseJToken(jtoken); return true; } /// public override bool TrySetMember(SetMemberBinder binder, object value) { if (!IsObject) throw new InvalidOperationException(IsNotJsonObject); var contains = _jobject.ContainsKey(binder.Name); if (contains) { _jobject[binder.Name] = ToJToken(value); return true; } else { _jobject.Add(binder.Name, ToJToken(value)); return true; } } private Class DynamicIndex(object[] indexes, Func stringCallback, Func intCallback) { var index = indexes[0]; if (index != null) { if (IsObject) { if (index is string name) return new Class(stringCallback.Invoke(name)); } if (IsArray) { if (index is int || index is short || index is byte || index is ushort || index is sbyte) { var int32 = int.Parse(index.ToString()); if (int32 < 0) throw new ArgumentOutOfRangeException("index", IndexLessZero); return new Class(intCallback(int32)); } else if (index is long int64) { if (int64 < 0) throw new ArgumentOutOfRangeException("index", IndexLessZero); if (int64 > int.MaxValue) throw new ArgumentOutOfRangeException("index", IndexGraterMax); var int32 = Convert.ToInt32(int64); return new Class(intCallback(int32)); } else if (index is uint uint32) { if (uint32 > int.MaxValue) throw new ArgumentOutOfRangeException("index", IndexGraterMax); var int32 = Convert.ToInt32(uint32); return new Class(intCallback(int32)); } else if (index is ulong uint64) { if (uint64 > int.MaxValue) throw new ArgumentOutOfRangeException("index", IndexGraterMax); var int32 = Convert.ToInt32(uint64); return new Class(intCallback(int32)); } } } throw new InvalidOperationException(InvalidIndex); } /// public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { var box = DynamicIndex(indexes, name => { var property = GetProperty(name); return ParseJToken(property?._jtoken); }, index => { return GetItem(index); }); if (box == null) { result = null; return false; } else { result = box.Value; return true; } } /// public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { var box = DynamicIndex(indexes, name => { _jobject[name] = ToJToken(value); return true; }, index => { SetItem(index, value); return true; }); return box != null; } /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { switch (binder.CallInfo.ArgumentNames.First().Lower()) { case "tostring": if (args == null) { result = ToString(); return true; } else { switch (args.Length) { case 0: result = ToString(); return true; case 1: if (args[0] == null) { result = null; return false; } else { if (args[0] is bool indented) { result = ToString(indented); return true; } else if (args[0] is byte int8) { result = ToString(int8 == 1); return true; } else if (args[0] is short int16) { result = ToString(int16 == 1); return true; } else if (args[0] is int int32) { result = ToString(int32 == 1); return true; } else if (args[0] is long int64) { result = ToString(int64 == 1); return true; } else { result = null; return false; } } default: result = null; return false; } } default: result = null; return false; } } /// public override bool TryConvert(ConvertBinder binder, out object result) { if (binder.Type.Equals(typeof(Json))) { result = this; return true; } if (binder.Type.Equals(typeof(string))) { result = ToString(); return true; } result = null; return false; } #endif #endregion #region 运算符。 /// 从 Json 到 Boolean 的隐式转换,判断 Json 对象可用。 public static implicit operator bool(Json json) => json != null && json.Available; /// 从 Json 到 String 的隐式转换,默认不缩进。 public static implicit operator string(Json json) => Export(json, false); /// 从 String 到 Json 的隐式转换。 /// public static implicit operator Json(string text) => From(text); #endregion #region Statics #region 创建实例。 /// 创建新对象。 public static Json NewObject() { return new Json(new JObject()); } /// 创建新对象。 public static Json NewObject(Dictionary dictionary) { var json = new Json(null); json.Reset(dictionary); return json; } /// 创建新对象。 public static Json NewObject(TextSet dictionary) { var json = new Json(null); json.Reset(dictionary); return json; } /// 创建新对象。 public static Json NewObject(ObjectSet dictionary) { var json = new Json(null); json.Reset(dictionary); return json; } /// 创建新对象。 public static Json NewArray() { return new Json(new JArray()); } /// 新建类型为 Property 的实例,值为 Null,失败时返回 Null。 /// Property 名称,不可为 Null。 /// public static Json NewProperty(string name) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, null)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, string value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, bool value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, int value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, long value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, float value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, double value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, decimal value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } return new Json(new JProperty(name, value)); } /// 新建类型为 Property 的实例,失败时返回 Null。 /// Property 名称,不可为 Null。 /// Property 值。 /// public static Json NewProperty(string name, Json value) { if (name == null) { if (AllowException) throw new ArgumentNullException("name", "参数无效。"); return null; } if (value == null) return new Json(new JProperty(name, null)); return new Json(new JProperty(name, null)); } #endregion /// 格式化 Json 文本。 public static string Format(string text) { if (text == null || text == "") return ""; try { var serializer = new Newtonsoft.Json.JsonSerializer(); var tr = (System.IO.TextReader)(new System.IO.StringReader(text)); var jtr = new Newtonsoft.Json.JsonTextReader(tr); var obj = serializer.Deserialize(jtr); if (obj != null) { var textWriter = new System.IO.StringWriter(); var jsonWriter = new Newtonsoft.Json.JsonTextWriter(textWriter) { Formatting = Newtonsoft.Json.Formatting.Indented, Indentation = 4, IndentChar = ' ' }; serializer.Serialize(jsonWriter, obj); return textWriter.ToString(); } else { return text; } } catch { return text ?? ""; } } /// 重命名属性名称。 public static Json Rename(Json json, Func renamer) { if (json == null) return null; switch (json.TokenType) { case JTokenType.Array: var items = json.GetItems(); foreach (var i in items) Rename(i, renamer); break; case JTokenType.Object: var properties = json.GetProperties(); foreach (var i in properties) { var name = i._jproperty.Name; var value = i._jproperty.Value; if (!string.IsNullOrEmpty(name)) { var newName = renamer(name); var newValue = Rename(new Json(value), renamer)?._jtoken; if (name != newName) { i.Remove(); json._jobject.Add(newName, newValue ?? value); } } } break; } return json; } /// 设置属性名称为小写。 public static Json Lower(Json json) => Rename(json, (old) => old.Lower()); /// 设置属性名称为驼峰形式。 public static Json Camel(Json json) => Rename(json, (old) => TextUtility.Camel(old)); private static bool CanSerialize(Type type, bool inherit = false) { if (type == null) return false; if (type.BaseType.Equals(typeof(Array))) return true; var interfaces = type.GetInterfaces(); foreach (var i in interfaces) { if (i.Equals(typeof(IList))) return true; } if (type.Equals(typeof(object))) return false; var sas = type.GetCustomAttributes(typeof(SerializableAttribute), inherit); if (sas != null && sas.Length > 0) return true; var tas = type.GetCustomAttributes(typeof(Source.TableAttribute), inherit); if (tas != null && tas.Length > 0) return true; return false; } /// 序列化指定对象为 JSON 字符串。 /// public static string SerializeObject(object @object, Type type = null, bool indented = false, string onError = null) => JsonConvert.SerializeObject(@object, type, indented ? Formatting.Indented : Formatting.None, null); /// 反序列化 JSON 字符串为指定的类型。 /// public static T DeserializeObject(string json) => (T)DeserializeObject(json, typeof(T)); /// 反序列化 JSON 字符串为指定的类型。 /// public static object DeserializeObject(string json, Type type = null) => JsonConvert.DeserializeObject(json, type, (JsonSerializerSettings)null); #if !NET20 /// 反序列化 JSON 字符串为指定的类型列表。 /// 要反序列化的类型。 /// 将要反序列化的 JSON 字符串。 /// 发生错误时返回 NULL 值,设置为 FALSE 时返回空 List<> 对象。 /// public static T[] DeserializeArray(string json, bool returnNullOnError = false) where T : class { try { var serializer = new JsonSerializer(); var @object = null as object; using (var sr = new StringReader(json)) { using (var jtr = new JsonTextReader(sr)) { @object = serializer.Deserialize(jtr, typeof(T[])); } } return (@object as T[]) ?? new T[0]; } catch { return returnNullOnError ? null : new T[0]; } } #endif #endregion #region DateTime static Func _datetime_serializer = null; static Func _datetime_deserializer = null; /// 自定义 DateTime 序列化程序。 public static Func DateTimeSerializer { get => _datetime_serializer; set => _datetime_serializer = value; } /// 自定义 DateTime 反序列化程序。 public static Func DateTimeDeserializer { get => _datetime_deserializer; set => _datetime_deserializer = value; } /// 序列化 DateTime 实例。 public static string SerializeDateTime(DateTime dateTime) { var serializer = _datetime_serializer; if (serializer != null) return serializer.Invoke(dateTime); return ClockUtility.Lucid(dateTime); } /// 序列化 DateTime 实例。 public static DateTime DeserializeDateTime(object value) { var deserializer = _datetime_deserializer; if (deserializer != null) return deserializer.Invoke(value); try { if (value is DateTime dt) return dt; var text = value.ToString(); var parse = ClockUtility.Parse(text); if (parse != null) return parse.Value; } catch { } return default; } #endregion } }