Reputation: 153
I am working with a cut down version of C# 3.5 on a platform that doesn't have the flexibility of using third party libraries.
While I can parse JSON (using a json stream reader), I am not sure how to actually turn it into a class. (there is also no access to the usual json to class deserializer).
Does anyone know how to use reflection to manually (yet dynamically) turn a JSON string into a class?
sample Json:
{"items":[
{"firstName":"bob", "lastName":"smith", "id":1001, "foods": [{"name":"fish", "name":"bacon", "name":"cereal"}]},
{"firstName":"sarah", "lastName":"smith", "id":1002, "foods": [{"name":"bacon", "name":"apples", "name":"chocolate"}]},
{"firstName":"tom", "lastName":"waffle", "id":1003, "foods": [{"name":"waffles", "name":"sticks", "name":"stones"}]},
{"firstName":"reginald", "lastName":"hamtuft", "id":1003, "foods": [{"name":"ham", "name":"cigars", "name":"noisy children"}]}
]}
Upvotes: 1
Views: 10681
Reputation: 157
Thanks Pete and the rest for getting me on the right track for this. In my case I also had to deserialize a JSON string to a Strongly Typed object in a SQL CLR Function, so I was limited on the libraries I could use "safely" (more info here).
I modified the code for ParseJSON, which deserializes into a Dictionary<string, object>
to be able to deserialize arrays of arrays, which it couldn't do, I also developed some methods to cast the resulting Dictionary into a Strongly Typed Object without using the JavaScriptConverter
or the System.Runtime.Serialization
library, with this code we are able to do the following:
//we have a foo and bar classes with a variety of fields and properties
private class foo
{
public List<double[][]> data;
public IEnumerable<object> DataObj;
public int integerField;
public long longProperty { get; set; }
public string stringValue;
public int? nullableInt;
public DateTime dateTimeValue;
public List<bar> classValues;
}
private class bar
{
public string stringValue;
public DateTimeOffset dateTimeOffsetValue;
}
static void Main(string[] args)
{
//lets deserialize the following JSON string into our foo object,
//the dictionary is optional, and not necessary if our JSON property names are the same as in our object.
//in this case it's used to map the "jdata" property on the JSON string to the "data" property of our object,
//in the case of the "dataObj", we are mapping to the uppercase field of our object
string JSONstring = "{\"jdata\":[[[1526518800000,7.0],[1526518834200,7.0]],[[1526549272200,25.0],[1526549306400,25.0]]],\"dataObj\":[[[1526518800000,7.0],[1526518834200,7.0]],\"abc\",123],\"integerField\":623,\"longProperty\":456789,\"stringValue\":\"foo\",\"nullableInt\":\"\",\"dateTimeValue\":\"2018-05-17T01:00:00.0000000\", \"classValues\": [{\"stringValue\":\"test\",\"dateTimeOffsetValue\":\"2018-05-17T05:00:00.0000000\"},{\"stringValue\":\"test2\",\"dateTimeOffsetValue\":\"2018-05-17T06:00:00.0000000\"}]}";
var mappingDict = new Dictionary<string, string>() { { "jdata", "data" }, { "dataObj", "DataObj" } };
foo myObject = ParseJSON<foo>(JSONstring, mappingDict);
}
The ParseJSON method will take a JSON string as input and optionally a Dictionary<string, string>
and will attempt to cast it into the Type T
the dictionary is used to map any property on the JSON string into a property of the object (for example, the "jdata"/"data" dictionary declared above).
public static T ParseJSON<T>(string jsonString, Dictionary<string, string> mappingTable = null)
{
Dictionary<string, object> jsonDictionary = ParseJSON(jsonString);
T castedObj = CastAs<T>(jsonDictionary, mappingTable);
return castedObj;
}
The following is my modified method for JSON parsing (can parse arrays of arrays):
public static Dictionary<string, object> ParseJSON(string json)
{
int end;
return ParseJSON(json, 0, out end);
}
private static Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
bool escbegin = false;
bool escend = false;
bool inquotes = false;
string key = null;
int cend;
StringBuilder sb = new StringBuilder();
Dictionary<string, object> child = null;
List<object> arraylist = null;
Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
int autoKey = 0;
int subArrayCount = 0;
List<int> arrayIndexes = new List<int>();
bool inSingleQuotes = false;
bool inDoubleQuotes = false;
for (int i = start; i < json.Length; i++)
{
char c = json[i];
if (c == '\\') escbegin = !escbegin;
if (!escbegin)
{
if (c == '"' && !inSingleQuotes)
{
inDoubleQuotes = !inDoubleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
else if (c == '\'' && !inDoubleQuotes)
{
inSingleQuotes = !inSingleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
if (!inquotes)
{
switch (c)
{
case '{':
if (i != start)
{
child = ParseJSON(json, i, out cend);
if (arraylist != null)
{
arraylist.Add(child);
}
else
{
dict.Add(key.Trim(), child);
key = null;
}
i = cend;
}
continue;
case '}':
end = i;
if (key != null)
{
if (arraylist != null) dict.Add(key.Trim(), arraylist);
else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
}
return dict;
case '[':
if (arraylist != null)
{
List<object> _tempArrayList = arraylist;
for (int l = 0; l < subArrayCount; l++)
{
if (l == subArrayCount - 1)
{
_tempArrayList.Add(new List<object>());
}
else
{
_tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
}
}
if (arrayIndexes.Count < subArrayCount)
{
arrayIndexes.Add(0);
}
subArrayCount++;
}
else
{
arraylist = new List<object>();
subArrayCount++;
}
continue;
case ']':
if (key == null)
{
key = "array" + autoKey.ToString();
autoKey++;
}
if (arraylist != null)
{
List<object> _tempArrayList = arraylist;
for (int l = 0; l < subArrayCount; l++)
{
if (l == subArrayCount - 1)
{
if (sb.Length > 0)
{
_tempArrayList.Add(sb.ToString());
}
subArrayCount--;
if (subArrayCount == arrayIndexes.Count)
{
if (arrayIndexes.Count > 0)
{
arrayIndexes[arrayIndexes.Count - 1]++;
}
}
else if (subArrayCount == arrayIndexes.Count - 1)
{
arrayIndexes.RemoveAt(arrayIndexes.Count - 1);
if (arrayIndexes.Count > 0)
{
arrayIndexes[arrayIndexes.Count - 1]++;
}
}
}
else
{
_tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
}
}
sb.Length = 0;
}
if (subArrayCount == 0)
{
dict.Add(key.Trim(), arraylist);
arraylist = null;
key = null;
}
continue;
case ',':
if (arraylist == null && key != null)
{
dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
key = null;
sb.Length = 0;
}
if (arraylist != null && sb.Length > 0)
{
List<object> _tempArrayList = arraylist;
for (int l = 0; l < subArrayCount; l++)
{
if (l == subArrayCount - 1)
{
_tempArrayList.Add(sb.ToString());
}
else
{
_tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
}
}
sb.Length = 0;
}
continue;
case ':':
key = DecodeString(regex, sb.ToString());
sb.Length = 0;
continue;
}
}
}
sb.Append(c);
if (escend) escbegin = false;
if (escbegin) escend = true;
else escend = false;
}
end = json.Length - 1;
return dict; //shouldn't ever get here unless the JSON is malformed
}
private static string DecodeString(Regex regex, string str)
{
return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}
The following methods attempt to cast the returned dictionary from the previous method into a Strong Typed Object, I know is lengthy but it does the job:
private static T CastAs<T>(Dictionary<string, object> source, Dictionary<string, string> mappingTable = null)
{
T outputData = (T)Activator.CreateInstance(typeof(T));
TrySet(outputData, source, mappingTable);
return outputData;
}
private static void TrySet(object target, Dictionary<string, object> source, Dictionary<string, string> mappingTable = null)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
bool useMappingTable = mappingTable != null && mappingTable.Count > 0;
foreach (KeyValuePair<string, object> kv in source)
{
string propertyName = null;
if (useMappingTable && mappingTable.ContainsKey(kv.Key))
{
propertyName = mappingTable[kv.Key];
}
else
{
propertyName = kv.Key;
}
if (!string.IsNullOrEmpty(propertyName))
{
UpdateMember(target, propertyName, kv.Value, mappingTable);
}
}
}
private static void UpdateMember(object target, string propertyName, object value, Dictionary<string, string> mappingTable)
{
try
{
FieldInfo fieldInfo = target.GetType().GetField(propertyName);
if (fieldInfo != null)
{
value = ConvertTo(value, fieldInfo.FieldType, mappingTable);
fieldInfo.SetValue(target, value);
}
else
{
PropertyInfo propInfo = target.GetType().GetProperty(propertyName);
if (propInfo != null)
{
value = ConvertTo(value, propInfo.PropertyType, mappingTable);
propInfo.SetValue(target, value);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
private static object ConvertTo(object value, Type targetType, Dictionary<string, string> mappingTable)
{
try
{
bool isNullable = false;
Type sourceType = value.GetType();
//Obtain actual type to convert to (this is necessary in case of Nullable types)
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
isNullable = true;
targetType = targetType.GetGenericArguments()[0];
}
if (isNullable && string.IsNullOrWhiteSpace(Convert.ToString(value)))
{
return null;
}
//if we are converting from a dictionary to a class, call the TrySet method to convert its members
else if (targetType.IsClass && sourceType.IsGenericType && sourceType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
//make sure our value is actually a Dictionary<string, object> in order to be able to cast
if (sourceType.GetGenericArguments()[0] == typeof(string))
{
object convertedValue = Activator.CreateInstance(targetType);
TrySet(convertedValue, (Dictionary<string, object>)value, mappingTable);
return convertedValue;
}
return null;
}
else if (IsCollection(value))
{
Type elementType = GetCollectionElementType(targetType);
if (elementType != null)
{
if (targetType.BaseType == typeof(Array))
{
return ConvertToArray(elementType, value, mappingTable);
}
else
{
return ConvertToList(elementType, value, mappingTable);
}
}
else
{
throw new NullReferenceException();
}
}
else if (targetType == typeof(DateTimeOffset))
{
return new DateTimeOffset((DateTime)ChangeType(value, typeof(DateTime)));
}
else if (targetType == typeof(object))
{
return value;
}
else
{
return ChangeType(value, targetType);
}
}
catch (Exception ex)
{
if (targetType.IsValueType)
{
return Activator.CreateInstance(targetType);
}
return null;
}
}
private static Array ConvertToArray(Type elementType, object value, Dictionary<string, string> mappingTable)
{
Array collection = Array.CreateInstance(elementType, ((ICollection)value).Count);
int i = 0;
foreach (object item in (IEnumerable)value)
{
try
{
collection.SetValue(ConvertTo(item, elementType, mappingTable), i);
i++;
}
catch (Exception ex)
{
//nothing here, just skip the item
}
}
return collection;
}
private static IList ConvertToList(Type elementType, object value, Dictionary<string, string> mappingTable)
{
Type listType = typeof(List<>);
Type constructedListType = listType.MakeGenericType(elementType);
IList collection = (IList)Activator.CreateInstance(constructedListType);
foreach (object item in (IEnumerable)value)
{
try
{
collection.Add(ConvertTo(item, elementType, mappingTable));
}
catch (Exception ex)
{
//nothing here, just skip the item
}
}
return collection;
}
private static bool IsCollection(object obj)
{
bool isCollection = false;
Type objType = obj.GetType();
if (!typeof(string).IsAssignableFrom(objType) && typeof(IEnumerable).IsAssignableFrom(objType))
{
isCollection = true;
}
return isCollection;
}
private static Type GetCollectionElementType(Type objType)
{
Type elementType;
Type[] genericArgs = objType.GenericTypeArguments;
if (genericArgs.Length > 0)
{
elementType = genericArgs[0];
}
else
{
elementType = objType.GetElementType();
}
return elementType;
}
private static object ChangeType(object value, Type castTo)
{
try
{
return Convert.ChangeType(value, castTo);
}
catch (Exception ex)
{
//if the conversion failed, just return the original value
return value;
}
}
I hope this is helpful to anyone still looking for a way to do this.
Upvotes: 3
Reputation: 4020
Thanks again to Pete and the other guys for their brilliant post. I have wrapped mine around a SQL Server CLR scalar function which was incredibly useful in interrogating JSON stored in relational tables (I know some would say just use MongoDB!).
Please see below:
public class JsonHelper
{
/// <summary>
/// Parses the JSON.
/// Thanks to http://stackoverflow.com/questions/14967618/deserialize-json-to-class-manually-with-reflection
/// </summary>
/// <param name="json">The json.</param>
/// <returns></returns>
public static Dictionary<string, object> DeserializeJson(string json)
{
int end;
return DeserializeJson(json, 0, out end);
}
/// <summary>
/// Parses the JSON.
/// </summary>
/// <param name="json">The json.</param>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
/// <returns></returns>
private static Dictionary<string, object> DeserializeJson(string json, int start, out int end)
{
var dict = new Dictionary<string, object>();
var escbegin = false;
var escend = false;
var inquotes = false;
string key = null;
var sb = new StringBuilder();
List<object> arraylist = null;
var regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
var autoKey = 0;
var inSingleQuotes = false;
var inDoubleQuotes = false;
for (var i = start; i < json.Length; i++)
{
var c = json[i];
if (c == '\\') escbegin = !escbegin;
if (!escbegin)
{
if (c == '"' && !inSingleQuotes)
{
inDoubleQuotes = !inDoubleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
if (c == '\'' && !inDoubleQuotes)
{
inSingleQuotes = !inSingleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
if (!inquotes)
{
switch (c)
{
case '{':
if (i != start)
{
int cend;
var child = DeserializeJson(json, i, out cend);
if (arraylist != null)
{
arraylist.Add(child);
}
else
{
dict.Add(key.Trim(), child);
key = null;
}
i = cend;
}
continue;
case '}':
end = i;
if (key != null)
{
if (arraylist != null) dict.Add(key.Trim(), arraylist);
else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
}
return dict;
case '[':
arraylist = new List<object>();
continue;
case ']':
if (key == null)
{
key = "array" + autoKey;
autoKey++;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
dict.Add(key.Trim(), arraylist);
arraylist = null;
key = null;
continue;
case ',':
if (arraylist == null && key != null)
{
dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
key = null;
sb.Length = 0;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
continue;
case ':':
key = DecodeString(regex, sb.ToString());
sb.Length = 0;
continue;
}
}
}
sb.Append(c);
if (escend) escbegin = false;
escend = escbegin;
}
end = json.Length - 1;
return dict; // theoretically shouldn't ever get here
}
/// <summary>
/// Decodes the string.
/// </summary>
/// <param name="regex">The regex.</param>
/// <param name="str">The STR.</param>
/// <returns></returns>
private static string DecodeString(Regex regex, string str)
{
return
Regex.Unescape(regex.Replace(str,
match =>
char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value,
System.Globalization.NumberStyles
.HexNumber))));
}
/// <summary>
/// Returns true if string has an "appearance" of being JSON-like
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsJson(string input)
{
input = input.Trim();
return input.StartsWith("{") && input.EndsWith("}")
|| input.StartsWith("[") && input.EndsWith("]");
}
}
The CLR function is below:
/// <summary>
/// Json "extractor" capable of extracting a value of a key using the object notation.
/// </summary>
/// <param name="json"></param>
/// <param name="key"></param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString fn_GetKeyValue(SqlString json, SqlString key)
{
var jsonString = json.ToString();
// Return if N/A
if (string.IsNullOrEmpty(jsonString) || !JsonHelper.IsJson(jsonString))
{
return json;
}
var keyString = key.ToString();
var jsonDictionary = JsonHelper.DeserializeJson(jsonString);
var lastNode = string.Empty;
foreach (var node in keyString.Split('.'))
{
if (!jsonDictionary.ContainsKey(node)) continue;
var childDictionary = jsonDictionary[node] as Dictionary<string, object>;
if (childDictionary != null)
{
jsonDictionary = childDictionary;
}
lastNode = node;
}
if (!jsonDictionary.ContainsKey(lastNode))
{
return null;
}
var keyValueString = jsonDictionary[lastNode].ToString();
return keyValueString == "null" ? null : new SqlString(keyValueString);
}
Usage would be:
-- Example 1 (querying a parent node)
SELECT dbo.fn_GetKeyValue('{
"ExchangeRates": {
"GBP": "1.2",
"USD": "2.0"
},
"Timestamp": "2015-04-10"
}', 'Timestamp');
-- Example 2 (querying a child node using a dot notation)
SELECT dbo.fn_GetKeyValue('{
"ExchangeRates": {
"GBP": "1.2",
"USD": "2.0"
},
"Timestamp": "2015-04-10"
}', 'ExchangeRates.GBP');
Upvotes: 1
Reputation: 6723
Okay, I'm redoing my answer based on the feedback. The dynamic object generator code still comes from this:
Deserialize JSON into C# dynamic object?
This uses RegEx, Generic collections and it does use Linq, but only in 2 lines and those can easily rewritten to not use Linq (the two 'result = ' lines at the end of DynamicJsonObject.TryGetMember()
). The generic dictionaries can also be replaced with hash tables if necessary.
The json parser is adapted from How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?
class Program
{
static void Main(string[] args)
{
string data = "{ 'test': 42, 'test2': 'test2\"', 'structure' : { 'field1': 'field1', 'field2': 44 } }";
dynamic x = new DynamicJsonObject(JsonMaker.ParseJSON(data));
Console.WriteLine(x.test2);
Console.WriteLine(x.structure.field1);
Console.ReadLine();
}
}
public class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _dictionary;
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public override string ToString()
{
var sb = new StringBuilder();
ToString(sb);
return sb.ToString();
}
private void ToString(StringBuilder sb)
{
sb.Append("{");
var firstInDictionary = true;
foreach (var pair in _dictionary)
{
if (!firstInDictionary)
sb.Append(",");
firstInDictionary = false;
var value = pair.Value;
var name = pair.Key;
if (value is string)
{
sb.AppendFormat("\"{0}\":\"{1}\"", name, value);
}
else if (value is IDictionary<string, object>)
{
sb.AppendFormat("\"{0}\":", name);
new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
}
else if (value is ArrayList)
{
sb.Append("\"");
sb.Append(name);
sb.Append("\":[");
var firstInArray = true;
foreach (var arrayValue in (ArrayList)value)
{
if (!firstInArray)
sb.Append(",");
firstInArray = false;
if (arrayValue is IDictionary<string, object>)
new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
else if (arrayValue is string)
sb.AppendFormat("\"{0}\"", arrayValue);
else
sb.AppendFormat("{0}", arrayValue);
}
sb.Append("]");
}
else
{
sb.AppendFormat("\"{0}\":{1}", name, value);
}
}
sb.Append("}");
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!_dictionary.TryGetValue(binder.Name, out result))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
var dictionary = result as IDictionary<string, object>;
if (dictionary != null)
{
result = new DynamicJsonObject(dictionary);
return true;
}
var arrayList = result as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
if (arrayList[0] is IDictionary<string, object>)
result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)));
else
result = new List<object>(arrayList.Cast<object>());
}
return true;
}
}
public static class JsonMaker
{
public static Dictionary<string, object> ParseJSON(string json)
{
int end;
return ParseJSON(json, 0, out end);
}
private static Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
bool escbegin = false;
bool escend = false;
bool inquotes = false;
string key = null;
int cend;
StringBuilder sb = new StringBuilder();
Dictionary<string, object> child = null;
List<object> arraylist = null;
Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
int autoKey = 0;
bool inSingleQuotes = false;
bool inDoubleQuotes = false;
for (int i = start; i < json.Length; i++)
{
char c = json[i];
if (c == '\\') escbegin = !escbegin;
if (!escbegin)
{
if (c == '"' && !inSingleQuotes)
{
inDoubleQuotes = !inDoubleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
else if (c == '\'' && !inDoubleQuotes)
{
inSingleQuotes = !inSingleQuotes;
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
if (!inquotes)
{
switch (c)
{
case '{':
if (i != start)
{
child = ParseJSON(json, i, out cend);
if (arraylist != null) arraylist.Add(child);
else
{
dict.Add(key.Trim(), child);
key = null;
}
i = cend;
}
continue;
case '}':
end = i;
if (key != null)
{
if (arraylist != null) dict.Add(key.Trim(), arraylist);
else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
}
return dict;
case '[':
arraylist = new List<object>();
continue;
case ']':
if (key == null)
{
key = "array" + autoKey.ToString();
autoKey++;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
dict.Add(key.Trim(), arraylist);
arraylist = null;
key = null;
continue;
case ',':
if (arraylist == null && key != null)
{
dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
key = null;
sb.Length = 0;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
continue;
case ':':
key = DecodeString(regex, sb.ToString());
sb.Length = 0;
continue;
}
}
}
sb.Append(c);
if (escend) escbegin = false;
if (escbegin) escend = true;
else escend = false;
}
end = json.Length - 1;
return dict; //theoretically shouldn't ever get here
}
private static string DecodeString(Regex regex, string str)
{
return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}
}
Upvotes: 1