Last active
July 9, 2019 00:45
-
-
Save TouiSoraHe/2afa319555afda452560883f5a6b494b to your computer and use it in GitHub Desktop.
在C#中模拟JavaScript的动态类型
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace CrossPlatformJson | |
{ | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Text; | |
public class JavaScriptObject : IEnumerable<KeyValuePair<JavaScriptObject, JavaScriptObject>> | |
{ | |
public enum JavaScriptObjectType | |
{ | |
Null = 0, | |
Boolean = 1, | |
Number = 2, | |
String = 3, | |
Array = 4, | |
Object = 5 | |
} | |
private JavaScriptObjectType _type; | |
private object _baseValue; | |
private List<JavaScriptObject> _arrayValue; | |
private Dictionary<string, JavaScriptObject> _objectValue; | |
public JavaScriptObject(double value) | |
{ | |
Type = JavaScriptObjectType.Number; | |
_baseValue = value; | |
} | |
public JavaScriptObject(string value) | |
{ | |
Type = JavaScriptObjectType.String; | |
_baseValue = value; | |
} | |
public JavaScriptObject(bool value) | |
{ | |
Type = JavaScriptObjectType.Boolean; | |
_baseValue = value; | |
} | |
public JavaScriptObject(JavaScriptObjectType type = JavaScriptObjectType.Null) | |
{ | |
Type = type; | |
if (Type == JavaScriptObjectType.Object) | |
{ | |
_objectValue = new Dictionary<string, JavaScriptObject>(); | |
} | |
else if (Type == JavaScriptObjectType.Array) | |
{ | |
_arrayValue = new List<JavaScriptObject>(); | |
} | |
} | |
public double GetNumber() | |
{ | |
if (Type == JavaScriptObjectType.Number) | |
{ | |
return (double)_baseValue; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个数值类型"); | |
} | |
} | |
public string GetString() | |
{ | |
if (Type == JavaScriptObjectType.String) | |
{ | |
return (string)_baseValue; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个字符串类型"); | |
} | |
} | |
public bool GetBoolean() | |
{ | |
if (Type == JavaScriptObjectType.Boolean) | |
{ | |
return (bool)_baseValue; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个布尔值类型"); | |
} | |
} | |
public JavaScriptObject this[int index] | |
{ | |
get | |
{ | |
if (Type != JavaScriptObjectType.Array) | |
{ | |
throw new Exception("该对象不是一个数组类型"); | |
} | |
return _arrayValue[index]; | |
} | |
set | |
{ | |
if (Type != JavaScriptObjectType.Array) | |
{ | |
throw new Exception("该对象不是一个数组类型"); | |
} | |
_arrayValue[index] = value; | |
} | |
} | |
public JavaScriptObject this[string key] | |
{ | |
get | |
{ | |
if (Type != JavaScriptObjectType.Object) | |
{ | |
throw new Exception("该对象不是一个对象类型"); | |
} | |
return _objectValue[key]; | |
} | |
set | |
{ | |
if (Type != JavaScriptObjectType.Object) | |
{ | |
throw new Exception("该对象不是一个对象类型"); | |
} | |
_objectValue[key] = value; | |
} | |
} | |
public void Add(JavaScriptObject value) | |
{ | |
if (Type == JavaScriptObjectType.Null) | |
{ | |
Type = JavaScriptObjectType.Array; | |
_arrayValue = new List<JavaScriptObject>(); | |
} | |
if (Type != JavaScriptObjectType.Array) | |
{ | |
throw new Exception("该对象不是一个数组类型"); | |
} | |
_arrayValue.Add(value); | |
} | |
public void Add(double value) | |
{ | |
Add(new JavaScriptObject(value)); | |
} | |
public void Add(string value) | |
{ | |
Add(new JavaScriptObject(value)); | |
} | |
public void Add(bool value) | |
{ | |
Add(new JavaScriptObject(value)); | |
} | |
public void Add(string key, JavaScriptObject value) | |
{ | |
if (Type == JavaScriptObjectType.Null) | |
{ | |
Type = JavaScriptObjectType.Object; | |
_objectValue = new Dictionary<string, JavaScriptObject>(); | |
} | |
if (Type != JavaScriptObjectType.Object) | |
{ | |
throw new Exception("该对象不是一个对象类型"); | |
} | |
_objectValue.Add(key, value); | |
} | |
public void Add(string key, double value) | |
{ | |
Add(key, new JavaScriptObject(value)); | |
} | |
public void Add(string key, string value) | |
{ | |
Add(key, new JavaScriptObject(value)); | |
} | |
public void Add(string key, bool value) | |
{ | |
Add(key, new JavaScriptObject(value)); | |
} | |
public void Remove(int index) | |
{ | |
if (Type != JavaScriptObjectType.Array) | |
{ | |
throw new Exception("该对象不是一个数组类型"); | |
} | |
_arrayValue.RemoveAt(index); | |
} | |
public void Remove(string key) | |
{ | |
if (Type != JavaScriptObjectType.Object) | |
{ | |
throw new Exception("该对象不是一个对象类型"); | |
} | |
_objectValue.Remove(key); | |
} | |
public bool ContainsKey(string key) | |
{ | |
if (Type != JavaScriptObjectType.Object) | |
{ | |
throw new Exception("该对象不是一个对象类型"); | |
} | |
return _objectValue.ContainsKey(key); | |
} | |
public void Clear() | |
{ | |
if (_objectValue != null) | |
{ | |
_objectValue.Clear(); | |
} | |
if (_arrayValue != null) | |
{ | |
_arrayValue.Clear(); | |
} | |
} | |
public int Count | |
{ | |
get | |
{ | |
switch (Type) | |
{ | |
case JavaScriptObjectType.Null: | |
return 0; | |
case JavaScriptObjectType.Boolean: | |
return 1; | |
case JavaScriptObjectType.Number: | |
return 1; | |
case JavaScriptObjectType.String: | |
return 1; | |
case JavaScriptObjectType.Array: | |
return _arrayValue.Count; | |
case JavaScriptObjectType.Object: | |
return _objectValue.Count; | |
default: | |
return -1; | |
} | |
} | |
} | |
public JavaScriptObjectType Type | |
{ | |
get | |
{ | |
return _type; | |
} | |
private set | |
{ | |
_type = value; | |
} | |
} | |
public void SetNumber(double value) | |
{ | |
if (Type == JavaScriptObjectType.Null) | |
{ | |
Type = JavaScriptObjectType.Number; | |
} | |
if (Type == JavaScriptObjectType.Number) | |
{ | |
_baseValue = value; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个数值类型"); | |
} | |
} | |
public void SetString(string value) | |
{ | |
if (Type == JavaScriptObjectType.Null) | |
{ | |
Type = JavaScriptObjectType.String; | |
} | |
if (Type == JavaScriptObjectType.String) | |
{ | |
_baseValue = value; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个字符串类型"); | |
} | |
} | |
public void SetBoolean(bool value) | |
{ | |
if (Type == JavaScriptObjectType.Null) | |
{ | |
Type = JavaScriptObjectType.Boolean; | |
} | |
if (Type == JavaScriptObjectType.Boolean) | |
{ | |
_baseValue = value; | |
} | |
else | |
{ | |
throw new Exception("该对象不是一个布尔值类型"); | |
} | |
} | |
public string ToJson() | |
{ | |
switch (Type) | |
{ | |
case JavaScriptObjectType.Null: | |
return "null"; | |
case JavaScriptObjectType.Boolean: | |
return GetBoolean() ? "true" : "false"; | |
case JavaScriptObjectType.Number: | |
return GetNumber().ToString(); | |
case JavaScriptObjectType.String: | |
return StringifyString(GetString()); | |
case JavaScriptObjectType.Array: | |
{ | |
StringBuilder ret = new StringBuilder(); | |
ret.Append("["); | |
for (int i = 0; i < _arrayValue.Count; i++) | |
{ | |
if (i != 0) | |
{ | |
ret.Append(","); | |
} | |
ret.Append(_arrayValue[i].ToJson()); | |
} | |
ret.Append("]"); | |
return ret.ToString(); | |
} | |
case JavaScriptObjectType.Object: | |
{ | |
StringBuilder ret = new StringBuilder(); | |
ret.Append("{"); | |
int index = 0; | |
foreach (var item in _objectValue) | |
{ | |
if (index != 0) | |
{ | |
ret.Append(","); | |
} | |
ret.Append(StringifyString(item.Key)); | |
ret.Append(":"); | |
ret.Append(item.Value.ToJson()); | |
index++; | |
} | |
ret.Append("}"); | |
return ret.ToString(); | |
} | |
default: | |
throw new Exception("意外的情况"); | |
} | |
} | |
private static readonly char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | |
private static string StringifyString(string value) | |
{ | |
StringBuilder str = new StringBuilder(); | |
str.Append("\""); | |
for (int i = 0; i < value.Length; i++) | |
{ | |
char ch = value[i]; | |
switch (ch) | |
{ | |
case '\"': str.Append( '\\'); str.Append('\"'); break; | |
case '\\': str.Append('\\'); str.Append('\\'); break; | |
case '\b': str.Append('\\'); str.Append('b'); break; | |
case '\f': str.Append('\\'); str.Append('f'); break; | |
case '\n': str.Append('\\'); str.Append('n'); break; | |
case '\r': str.Append('\\'); str.Append('r'); break; | |
case '\t': str.Append('\\'); str.Append('t'); break; | |
default: | |
if (ch < 0x20) | |
{ | |
str.Append('\\'); str.Append('u'); str.Append('0'); str.Append('0'); | |
str.Append(hexDigits[ch >> 4]); | |
str.Append(hexDigits[ch & 15]); | |
} | |
else | |
str.Append(ch); | |
break; | |
} | |
} | |
str.Append("\""); | |
return str.ToString(); | |
} | |
public override string ToString() | |
{ | |
return ToJson(); | |
} | |
public IEnumerator<KeyValuePair<JavaScriptObject, JavaScriptObject>> GetEnumerator() | |
{ | |
if (_type == JavaScriptObjectType.Object) | |
{ | |
foreach (var item in _objectValue) | |
{ | |
yield return new KeyValuePair<JavaScriptObject, JavaScriptObject>(new JavaScriptObject(item.Key), item.Value); | |
} | |
} | |
else if (_type == JavaScriptObjectType.Array) | |
{ | |
for (int i = 0; i < _arrayValue.Count; i++) | |
{ | |
yield return new KeyValuePair<JavaScriptObject, JavaScriptObject>(new JavaScriptObject(i), _arrayValue[i]); | |
} | |
} | |
else | |
{ | |
throw new NotImplementedException("迭代器只对数组或对象类型有效"); | |
} | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
throw new NotImplementedException(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment