//----------------------------------------------------------------------- // // Copyright (c) 2011, The Outercurve Foundation. // // Licensed under the MIT License (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.opensource.org/licenses/mit-license.php // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me) // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- // VERSION: // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL // NOTE: uncomment the following line to make JsonArray and JsonObject class internal. //#define SIMPLE_JSON_OBJARRAYINTERNAL // NOTE: uncomment the following line to enable dynamic support. //#define SIMPLE_JSON_DYNAMIC // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT // NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. //#define SIMPLE_JSON_READONLY_COLLECTIONS // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 #define SIMPLE_JSON_NO_LINQ_EXPRESSION // NOTE: uncomment the following line if you are compiling under Window Metro style application/library. // usually already defined in properties //#define NETFX_CORE; // If you are targetting WinStore, WP8 and NET4.5+ PCL make sure to #define SIMPLE_JSON_TYPEINFO; // original json parsing code from http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html #if NETFX_CORE #define SIMPLE_JSON_TYPEINFO #endif using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Runtime.Serialization; using System.Text; using Unity.Cloud.UserReporting.Plugin.SimpleJson.Reflection; #if !SIMPLE_JSON_NO_LINQ_EXPRESSION using System.Linq.Expressions; #endif #if SIMPLE_JSON_DYNAMIC using System.Dynamic; #endif // ReSharper disable LoopCanBeConvertedToQuery // ReSharper disable RedundantExplicitArrayCreation // ReSharper disable SuggestUseVarKeywordEvident namespace Unity.Cloud.UserReporting.Plugin.SimpleJson { [GeneratedCode("simple-json", "1.0.0")] [EditorBrowsable(EditorBrowsableState.Never)] [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] #if SIMPLE_JSON_OBJARRAYINTERNAL internal #else public #endif class JsonArray : List { public JsonArray() { } public JsonArray(int capacity) : base(capacity) { } public override string ToString() { return SimpleJson.SerializeObject(this) ?? string.Empty; } } [GeneratedCode("simple-json", "1.0.0")] [EditorBrowsable(EditorBrowsableState.Never)] [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] #if SIMPLE_JSON_OBJARRAYINTERNAL internal #else public #endif class JsonObject : #if SIMPLE_JSON_DYNAMIC DynamicObject, #endif IDictionary { private readonly Dictionary _members; public JsonObject() { _members = new Dictionary(); } public JsonObject(IEqualityComparer comparer) { _members = new Dictionary(comparer); } public object this[int index] { get { return JsonObject.GetAtIndex(_members, index); } } internal static object GetAtIndex(IDictionary obj, int index) { if (obj == null) { throw new ArgumentNullException("obj"); } if (index >= obj.Count) { throw new ArgumentOutOfRangeException("index"); } int i = 0; foreach (KeyValuePair o in obj) { if (i++ == index) { return o.Value; } } return null; } public void Add(string key, object value) { _members.Add(key, value); } public bool ContainsKey(string key) { return _members.ContainsKey(key); } public ICollection Keys { get { return _members.Keys; } } public bool Remove(string key) { return _members.Remove(key); } public bool TryGetValue(string key, out object value) { return _members.TryGetValue(key, out value); } public ICollection Values { get { return _members.Values; } } public object this[string key] { get { return _members[key]; } set { _members[key] = value; } } public void Add(KeyValuePair item) { _members.Add(item.Key, item.Value); } public void Clear() { _members.Clear(); } public bool Contains(KeyValuePair item) { return _members.ContainsKey(item.Key) && this._members[item.Key] == item.Value; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { throw new ArgumentNullException("array"); } int num = Count; foreach (KeyValuePair kvp in this) { array[arrayIndex++] = kvp; if (--num <= 0) { return; } } } public int Count { get { return _members.Count; } } public bool IsReadOnly { get { return false; } } public bool Remove(KeyValuePair item) { return _members.Remove(item.Key); } public IEnumerator> GetEnumerator() { return _members.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _members.GetEnumerator(); } public override string ToString() { return SimpleJson.SerializeObject(this); } #if SIMPLE_JSON_DYNAMIC public override bool TryConvert(ConvertBinder binder, out object result) { // if (binder == null) throw new ArgumentNullException("binder"); // Type targetType = binder.Type; if ((targetType == typeof(IEnumerable)) || (targetType == typeof(IEnumerable>)) || (targetType == typeof(IDictionary)) || (targetType == typeof(IDictionary))) { result = this; return true; } return base.TryConvert(binder, out result); } public override bool TryDeleteMember(DeleteMemberBinder binder) { // if (binder == null) throw new ArgumentNullException("binder"); // return _members.Remove(binder.Name); } public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes == null) throw new ArgumentNullException("indexes"); if (indexes.Length == 1) { result = ((IDictionary)this)[(string)indexes[0]]; return true; } result = null; return true; } public override bool TryGetMember(GetMemberBinder binder, out object result) { object value; if (_members.TryGetValue(binder.Name, out value)) { result = value; return true; } result = null; return true; } public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (indexes == null) throw new ArgumentNullException("indexes"); if (indexes.Length == 1) { ((IDictionary)this)[(string)indexes[0]] = value; return true; } return base.TrySetIndex(binder, indexes, value); } public override bool TrySetMember(SetMemberBinder binder, object value) { // if (binder == null) throw new ArgumentNullException("binder"); // _members[binder.Name] = value; return true; } public override IEnumerable GetDynamicMemberNames() { foreach (var key in Keys) yield return key; } #endif } } namespace Unity.Cloud.UserReporting.Plugin.SimpleJson { [GeneratedCode("simple-json", "1.0.0")] #if SIMPLE_JSON_INTERNAL internal #else public #endif static class SimpleJson { private const int TOKEN_NONE = 0; private const int TOKEN_CURLY_OPEN = 1; private const int TOKEN_CURLY_CLOSE = 2; private const int TOKEN_SQUARED_OPEN = 3; private const int TOKEN_SQUARED_CLOSE = 4; private const int TOKEN_COLON = 5; private const int TOKEN_COMMA = 6; private const int TOKEN_STRING = 7; private const int TOKEN_NUMBER = 8; private const int TOKEN_TRUE = 9; private const int TOKEN_FALSE = 10; private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; private static readonly char[] EscapeTable; private static readonly char[] EscapeCharacters = new char[] {'"', '\\', '\b', '\f', '\n', '\r', '\t'}; static SimpleJson() { SimpleJson.EscapeTable = new char[93]; SimpleJson.EscapeTable['"'] = '"'; SimpleJson.EscapeTable['\\'] = '\\'; SimpleJson.EscapeTable['\b'] = 'b'; SimpleJson.EscapeTable['\f'] = 'f'; SimpleJson.EscapeTable['\n'] = 'n'; SimpleJson.EscapeTable['\r'] = 'r'; SimpleJson.EscapeTable['\t'] = 't'; } public static object DeserializeObject(string json) { object obj; if (SimpleJson.TryDeserializeObject(json, out obj)) { return obj; } throw new SerializationException("Invalid JSON string"); } [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] public static bool TryDeserializeObject(string json, out object obj) { bool success = true; if (json != null) { char[] charArray = json.ToCharArray(); int index = 0; obj = SimpleJson.ParseValue(charArray, ref index, ref success); } else { obj = null; } return success; } public static object DeserializeObject(string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy) { object jsonObject = SimpleJson.DeserializeObject(json); return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type) ? jsonObject : (jsonSerializerStrategy ?? SimpleJson.CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type); } public static object DeserializeObject(string json, Type type) { return SimpleJson.DeserializeObject(json, type, null); } public static T DeserializeObject(string json, IJsonSerializerStrategy jsonSerializerStrategy) { return (T) SimpleJson.DeserializeObject(json, typeof(T), jsonSerializerStrategy); } public static T DeserializeObject(string json) { return (T) SimpleJson.DeserializeObject(json, typeof(T), null); } public static string SerializeObject(object json, IJsonSerializerStrategy jsonSerializerStrategy) { StringBuilder builder = new StringBuilder(SimpleJson.BUILDER_CAPACITY); bool success = SimpleJson.SerializeValue(jsonSerializerStrategy, json, builder); return success ? builder.ToString() : null; } public static string SerializeObject(object json) { return SimpleJson.SerializeObject(json, SimpleJson.CurrentJsonSerializerStrategy); } public static string EscapeToJavascriptString(string jsonString) { if (string.IsNullOrEmpty(jsonString)) { return jsonString; } StringBuilder sb = new StringBuilder(); char c; for (int i = 0; i < jsonString.Length;) { c = jsonString[i++]; if (c == '\\') { int remainingLength = jsonString.Length - i; if (remainingLength >= 2) { char lookahead = jsonString[i]; if (lookahead == '\\') { sb.Append('\\'); ++i; } else if (lookahead == '"') { sb.Append("\""); ++i; } else if (lookahead == 't') { sb.Append('\t'); ++i; } else if (lookahead == 'b') { sb.Append('\b'); ++i; } else if (lookahead == 'n') { sb.Append('\n'); ++i; } else if (lookahead == 'r') { sb.Append('\r'); ++i; } } } else { sb.Append(c); } } return sb.ToString(); } private static IDictionary ParseObject(char[] json, ref int index, ref bool success) { IDictionary table = new JsonObject(); int token; // { SimpleJson.NextToken(json, ref index); bool done = false; while (!done) { token = SimpleJson.LookAhead(json, index); if (token == SimpleJson.TOKEN_NONE) { success = false; return null; } else if (token == SimpleJson.TOKEN_COMMA) { SimpleJson.NextToken(json, ref index); } else if (token == SimpleJson.TOKEN_CURLY_CLOSE) { SimpleJson.NextToken(json, ref index); return table; } else { // name string name = SimpleJson.ParseString(json, ref index, ref success); if (!success) { success = false; return null; } // : token = SimpleJson.NextToken(json, ref index); if (token != SimpleJson.TOKEN_COLON) { success = false; return null; } // value object value = SimpleJson.ParseValue(json, ref index, ref success); if (!success) { success = false; return null; } table[name] = value; } } return table; } private static JsonArray ParseArray(char[] json, ref int index, ref bool success) { JsonArray array = new JsonArray(); // [ SimpleJson.NextToken(json, ref index); bool done = false; while (!done) { int token = SimpleJson.LookAhead(json, index); if (token == SimpleJson.TOKEN_NONE) { success = false; return null; } else if (token == SimpleJson.TOKEN_COMMA) { SimpleJson.NextToken(json, ref index); } else if (token == SimpleJson.TOKEN_SQUARED_CLOSE) { SimpleJson.NextToken(json, ref index); break; } else { object value = SimpleJson.ParseValue(json, ref index, ref success); if (!success) { return null; } array.Add(value); } } return array; } private static object ParseValue(char[] json, ref int index, ref bool success) { switch (SimpleJson.LookAhead(json, index)) { case SimpleJson.TOKEN_STRING: return SimpleJson.ParseString(json, ref index, ref success); case SimpleJson.TOKEN_NUMBER: return SimpleJson.ParseNumber(json, ref index, ref success); case SimpleJson.TOKEN_CURLY_OPEN: return SimpleJson.ParseObject(json, ref index, ref success); case SimpleJson.TOKEN_SQUARED_OPEN: return SimpleJson.ParseArray(json, ref index, ref success); case SimpleJson.TOKEN_TRUE: SimpleJson.NextToken(json, ref index); return true; case SimpleJson.TOKEN_FALSE: SimpleJson.NextToken(json, ref index); return false; case SimpleJson.TOKEN_NULL: SimpleJson.NextToken(json, ref index); return null; case SimpleJson.TOKEN_NONE: break; } success = false; return null; } private static string ParseString(char[] json, ref int index, ref bool success) { StringBuilder s = new StringBuilder(SimpleJson.BUILDER_CAPACITY); char c; SimpleJson.EatWhitespace(json, ref index); // " c = json[index++]; bool complete = false; while (!complete) { if (index == json.Length) { break; } c = json[index++]; if (c == '"') { complete = true; break; } else if (c == '\\') { if (index == json.Length) { break; } c = json[index++]; if (c == '"') { s.Append('"'); } else if (c == '\\') { s.Append('\\'); } else if (c == '/') { s.Append('/'); } else if (c == 'b') { s.Append('\b'); } else if (c == 'f') { s.Append('\f'); } else if (c == 'n') { s.Append('\n'); } else if (c == 'r') { s.Append('\r'); } else if (c == 't') { s.Append('\t'); } else if (c == 'u') { int remainingLength = json.Length - index; if (remainingLength >= 4) { // parse the 32 bit hex into an integer codepoint uint codePoint; if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) { return ""; } // convert the integer codepoint to a unicode char and add to string if (0xD800 <= codePoint && codePoint <= 0xDBFF) // if high surrogate { index += 4; // skip 4 chars remainingLength = json.Length - index; if (remainingLength >= 6) { uint lowCodePoint; if (new string(json, index, 2) == "\\u" && UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out lowCodePoint)) { if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF) // if low surrogate { s.Append((char) codePoint); s.Append((char) lowCodePoint); index += 6; // skip 6 chars continue; } } } success = false; // invalid surrogate pair return ""; } s.Append(SimpleJson.ConvertFromUtf32((int) codePoint)); // skip 4 chars index += 4; } else { break; } } } else { s.Append(c); } } if (!complete) { success = false; return null; } return s.ToString(); } private static string ConvertFromUtf32(int utf32) { // http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System/System/Char.cs.htm if (utf32 < 0 || utf32 > 0x10FFFF) { throw new ArgumentOutOfRangeException("utf32", "The argument must be from 0 to 0x10FFFF."); } if (0xD800 <= utf32 && utf32 <= 0xDFFF) { throw new ArgumentOutOfRangeException("utf32", "The argument must not be in surrogate pair range."); } if (utf32 < 0x10000) { return new string((char) utf32, 1); } utf32 -= 0x10000; return new string(new char[] {(char) ((utf32 >> 10) + 0xD800), (char) (utf32 % 0x0400 + 0xDC00)}); } private static object ParseNumber(char[] json, ref int index, ref bool success) { SimpleJson.EatWhitespace(json, ref index); int lastIndex = SimpleJson.GetLastIndexOfNumber(json, index); int charLength = lastIndex - index + 1; object returnNumber; string str = new string(json, index, charLength); if (str.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || str.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1) { double number; success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number); returnNumber = number; } else { long number; success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number); returnNumber = number; } index = lastIndex + 1; return returnNumber; } private static int GetLastIndexOfNumber(char[] json, int index) { int lastIndex; for (lastIndex = index; lastIndex < json.Length; lastIndex++) { if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) { break; } } return lastIndex - 1; } private static void EatWhitespace(char[] json, ref int index) { for (; index < json.Length; index++) { if (" \t\n\r\b\f".IndexOf(json[index]) == -1) { break; } } } private static int LookAhead(char[] json, int index) { int saveIndex = index; return SimpleJson.NextToken(json, ref saveIndex); } [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] private static int NextToken(char[] json, ref int index) { SimpleJson.EatWhitespace(json, ref index); if (index == json.Length) { return SimpleJson.TOKEN_NONE; } char c = json[index]; index++; switch (c) { case '{': return SimpleJson.TOKEN_CURLY_OPEN; case '}': return SimpleJson.TOKEN_CURLY_CLOSE; case '[': return SimpleJson.TOKEN_SQUARED_OPEN; case ']': return SimpleJson.TOKEN_SQUARED_CLOSE; case ',': return SimpleJson.TOKEN_COMMA; case '"': return SimpleJson.TOKEN_STRING; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return SimpleJson.TOKEN_NUMBER; case ':': return SimpleJson.TOKEN_COLON; } index--; int remainingLength = json.Length - index; // false if (remainingLength >= 5) { if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && json[index + 4] == 'e') { index += 5; return SimpleJson.TOKEN_FALSE; } } // true if (remainingLength >= 4) { if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e') { index += 4; return SimpleJson.TOKEN_TRUE; } } // null if (remainingLength >= 4) { if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l') { index += 4; return SimpleJson.TOKEN_NULL; } } return SimpleJson.TOKEN_NONE; } private static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, object value, StringBuilder builder) { bool success = true; string stringValue = value as string; if (stringValue != null) { success = SimpleJson.SerializeString(stringValue, builder); } else { IDictionary dict = value as IDictionary; if (dict != null) { success = SimpleJson.SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder); } else { IDictionary stringDictionary = value as IDictionary; if (stringDictionary != null) { success = SimpleJson.SerializeObject(jsonSerializerStrategy, stringDictionary.Keys, stringDictionary.Values, builder); } else { IEnumerable enumerableValue = value as IEnumerable; if (enumerableValue != null) { success = SimpleJson.SerializeArray(jsonSerializerStrategy, enumerableValue, builder); } else if (SimpleJson.IsNumeric(value)) { success = SimpleJson.SerializeNumber(value, builder); } else if (value is bool) { builder.Append((bool) value ? "true" : "false"); } else if (value == null) { builder.Append("null"); } else { object serializedObject; success = jsonSerializerStrategy.TrySerializeNonPrimitiveObject(value, out serializedObject); if (success) { SimpleJson.SerializeValue(jsonSerializerStrategy, serializedObject, builder); } } } } } return success; } private static bool SerializeObject(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable keys, IEnumerable values, StringBuilder builder) { builder.Append("{"); IEnumerator ke = keys.GetEnumerator(); IEnumerator ve = values.GetEnumerator(); bool first = true; while (ke.MoveNext() && ve.MoveNext()) { object key = ke.Current; object value = ve.Current; if (!first) { builder.Append(","); } string stringKey = key as string; if (stringKey != null) { SimpleJson.SerializeString(stringKey, builder); } else if (!SimpleJson.SerializeValue(jsonSerializerStrategy, value, builder)) { return false; } builder.Append(":"); if (!SimpleJson.SerializeValue(jsonSerializerStrategy, value, builder)) { return false; } first = false; } builder.Append("}"); return true; } private static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder) { builder.Append("["); bool first = true; foreach (object value in anArray) { if (!first) { builder.Append(","); } if (!SimpleJson.SerializeValue(jsonSerializerStrategy, value, builder)) { return false; } first = false; } builder.Append("]"); return true; } private static bool SerializeString(string aString, StringBuilder builder) { // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) if (aString.IndexOfAny(SimpleJson.EscapeCharacters) == -1) { builder.Append('"'); builder.Append(aString); builder.Append('"'); return true; } builder.Append('"'); int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; // Non ascii characters are fine, buffer them up and send them to the builder // in larger chunks if possible. The escape table is a 1:1 translation table // with \0 [default(char)] denoting a safe character. if (c >= SimpleJson.EscapeTable.Length || SimpleJson.EscapeTable[c] == default(char)) { safeCharacterCount++; } else { if (safeCharacterCount > 0) { builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); safeCharacterCount = 0; } builder.Append('\\'); builder.Append(SimpleJson.EscapeTable[c]); } } if (safeCharacterCount > 0) { builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); } builder.Append('"'); return true; } private static bool SerializeNumber(object number, StringBuilder builder) { if (number is long) { builder.Append(((long) number).ToString(CultureInfo.InvariantCulture)); } else if (number is ulong) { builder.Append(((ulong) number).ToString(CultureInfo.InvariantCulture)); } else if (number is int) { builder.Append(((int) number).ToString(CultureInfo.InvariantCulture)); } else if (number is uint) { builder.Append(((uint) number).ToString(CultureInfo.InvariantCulture)); } else if (number is decimal) { builder.Append(((decimal) number).ToString(CultureInfo.InvariantCulture)); } else if (number is float) { builder.Append(((float) number).ToString(CultureInfo.InvariantCulture)); } else { builder.Append(Convert.ToDouble(number, CultureInfo.InvariantCulture) .ToString("r", CultureInfo.InvariantCulture)); } return true; } private static bool IsNumeric(object value) { if (value is sbyte) { return true; } if (value is byte) { return true; } if (value is short) { return true; } if (value is ushort) { return true; } if (value is int) { return true; } if (value is uint) { return true; } if (value is long) { return true; } if (value is ulong) { return true; } if (value is float) { return true; } if (value is double) { return true; } if (value is decimal) { return true; } return false; } private static IJsonSerializerStrategy _currentJsonSerializerStrategy; public static IJsonSerializerStrategy CurrentJsonSerializerStrategy { get { return SimpleJson._currentJsonSerializerStrategy ?? (SimpleJson._currentJsonSerializerStrategy = #if SIMPLE_JSON_DATACONTRACT DataContractJsonSerializerStrategy #else SimpleJson.PocoJsonSerializerStrategy #endif ); } set { SimpleJson._currentJsonSerializerStrategy = value; } } private static PocoJsonSerializerStrategy _pocoJsonSerializerStrategy; [EditorBrowsable(EditorBrowsableState.Advanced)] public static PocoJsonSerializerStrategy PocoJsonSerializerStrategy { get { return SimpleJson._pocoJsonSerializerStrategy ?? (SimpleJson._pocoJsonSerializerStrategy = new PocoJsonSerializerStrategy()); } } #if SIMPLE_JSON_DATACONTRACT private static DataContractJsonSerializerStrategy _dataContractJsonSerializerStrategy; [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Advanced)] public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrategy { get { return _dataContractJsonSerializerStrategy ?? (_dataContractJsonSerializerStrategy = new DataContractJsonSerializerStrategy()); } } #endif } [GeneratedCode("simple-json", "1.0.0")] #if SIMPLE_JSON_INTERNAL internal #else public #endif interface IJsonSerializerStrategy { [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] bool TrySerializeNonPrimitiveObject(object input, out object output); object DeserializeObject(object value, Type type); } [GeneratedCode("simple-json", "1.0.0")] #if SIMPLE_JSON_INTERNAL internal #else public #endif class PocoJsonSerializerStrategy : IJsonSerializerStrategy { internal IDictionary ConstructorCache; internal IDictionary> GetCache; internal IDictionary>> SetCache; internal static readonly Type[] EmptyTypes = new Type[0]; internal static readonly Type[] ArrayConstructorParameterTypes = new Type[] {typeof(int)}; private static readonly string[] Iso8601Format = new string[] {@"yyyy-MM-dd\THH:mm:ss.FFFFFFF\Z", @"yyyy-MM-dd\THH:mm:ss\Z", @"yyyy-MM-dd\THH:mm:ssK"}; public PocoJsonSerializerStrategy() { ConstructorCache = new ReflectionUtils.ThreadSafeDictionary(ContructorDelegateFactory); GetCache = new ReflectionUtils.ThreadSafeDictionary>(GetterValueFactory); SetCache = new ReflectionUtils.ThreadSafeDictionary>>(SetterValueFactory); } protected virtual string MapClrMemberNameToJsonFieldName(string clrPropertyName) { return clrPropertyName; } internal virtual ReflectionUtils.ConstructorDelegate ContructorDelegateFactory(Type key) { return ReflectionUtils.GetContructor(key, key.IsArray ? PocoJsonSerializerStrategy.ArrayConstructorParameterTypes : PocoJsonSerializerStrategy.EmptyTypes); } internal virtual IDictionary GetterValueFactory(Type type) { IDictionary result = new Dictionary(); foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type)) { if (propertyInfo.CanRead) { MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo); if (getMethod.IsStatic || !getMethod.IsPublic) { continue; } result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = ReflectionUtils.GetGetMethod(propertyInfo); } } foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type)) { if (fieldInfo.IsStatic || !fieldInfo.IsPublic) { continue; } result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = ReflectionUtils.GetGetMethod(fieldInfo); } return result; } internal virtual IDictionary> SetterValueFactory(Type type) { IDictionary> result = new Dictionary>(); foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type)) { if (propertyInfo.CanWrite) { MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo); if (setMethod.IsStatic || !setMethod.IsPublic) { continue; } result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = new KeyValuePair(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo)); } } foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type)) { if (fieldInfo.IsInitOnly || fieldInfo.IsStatic || !fieldInfo.IsPublic) { continue; } result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = new KeyValuePair(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo)); } return result; } public virtual bool TrySerializeNonPrimitiveObject(object input, out object output) { return TrySerializeKnownTypes(input, out output) || TrySerializeUnknownTypes(input, out output); } [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] public virtual object DeserializeObject(object value, Type type) { if (type == null) { throw new ArgumentNullException("type"); } string str = value as string; if (type == typeof(Guid) && string.IsNullOrEmpty(str)) { return default(Guid); } if (value == null) { return null; } object obj = null; if (str != null) { if (str.Length != 0) // We know it can't be null now. { if (type == typeof(DateTime) || ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)) { return DateTime.ParseExact(str, PocoJsonSerializerStrategy.Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); } if (type == typeof(DateTimeOffset) || ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset)) { return DateTimeOffset.ParseExact(str, PocoJsonSerializerStrategy.Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); } if (type == typeof(Guid) || ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)) { return new Guid(str); } if (type == typeof(Uri)) { bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute); Uri result; if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result)) { return result; } return null; } if (type == typeof(string)) { return str; } if (type == typeof(TimeSpan) || ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(TimeSpan)) { return TimeSpan.Parse(str); } return Convert.ChangeType(str, type, CultureInfo.InvariantCulture); } else { if (type == typeof(Guid)) { obj = default(Guid); } else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)) { obj = null; } else { obj = str; } } // Empty string case if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)) { return str; } } if (type.IsEnum) { return Enum.Parse(type, value.ToString()); } else if (value is bool) { return value; } bool valueIsLong = value is long; bool valueIsDouble = value is double; if (valueIsLong && type == typeof(long) || valueIsDouble && type == typeof(double)) { return value; } if (valueIsDouble && type != typeof(double) || valueIsLong && type != typeof(long)) { obj = type == typeof(int) || type == typeof(long) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short) ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture) : value; } else { IDictionary objects = value as IDictionary; if (objects != null) { IDictionary jsonObject = objects; if (ReflectionUtils.IsTypeDictionary(type)) { // if dictionary then Type[] types = ReflectionUtils.GetGenericTypeArguments(type); Type keyType = types[0]; Type valueType = types[1]; Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); IDictionary dict = (IDictionary) ConstructorCache[genericType](); foreach (KeyValuePair kvp in jsonObject) { dict.Add(kvp.Key, this.DeserializeObject(kvp.Value, valueType)); } obj = dict; } else { if (type == typeof(object)) { obj = value; } else { obj = Activator.CreateInstance(type); foreach (KeyValuePair> setter in SetCache[type]) { object jsonValue; if (jsonObject.TryGetValue(setter.Key, out jsonValue)) { jsonValue = DeserializeObject(jsonValue, setter.Value.Key); setter.Value.Value(obj, jsonValue); } else { string camelKey = setter.Key; camelKey = char.ToLower(camelKey[0]) + camelKey.Substring(1); if (jsonObject.TryGetValue(camelKey, out jsonValue)) { jsonValue = DeserializeObject(jsonValue, setter.Value.Key); setter.Value.Value(obj, jsonValue); } } } } } } else { IList valueAsList = value as IList; if (valueAsList != null) { IList jsonObject = valueAsList; IList list = null; if (type.IsArray) { list = (IList) ConstructorCache[type](jsonObject.Count); int i = 0; foreach (object o in jsonObject) { list[i++] = this.DeserializeObject(o, type.GetElementType()); } } else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type)) { Type innerType = ReflectionUtils.GetGenericListElementType(type); list = (IList) (ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(); foreach (object o in jsonObject) { list.Add(this.DeserializeObject(o, innerType)); } } obj = list; } } return obj; } if (ReflectionUtils.IsNullableType(type)) { return ReflectionUtils.ToNullableType(obj, type); } return obj; } protected virtual object SerializeEnum(Enum p) { return Convert.ToDouble(p, CultureInfo.InvariantCulture); } [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] protected virtual bool TrySerializeKnownTypes(object input, out object output) { bool returnValue = true; if (input is DateTime) { output = ((DateTime) input).ToUniversalTime() .ToString(PocoJsonSerializerStrategy.Iso8601Format[0], CultureInfo.InvariantCulture); } else if (input is DateTimeOffset) { output = ((DateTimeOffset) input).ToUniversalTime() .ToString(PocoJsonSerializerStrategy.Iso8601Format[0], CultureInfo.InvariantCulture); } else if (input is TimeSpan) { output = ((TimeSpan) input).ToString(); } else if (input is Guid) { output = ((Guid) input).ToString("D"); } else if (input is Uri) { output = input.ToString(); } else { Enum inputEnum = input as Enum; if (inputEnum != null) { output = this.SerializeEnum(inputEnum); } else { returnValue = false; output = null; } } return returnValue; } [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] protected virtual bool TrySerializeUnknownTypes(object input, out object output) { if (input == null) { throw new ArgumentNullException("input"); } output = null; Type type = input.GetType(); if (type.FullName == null) { return false; } IDictionary obj = new JsonObject(); IDictionary getters = GetCache[type]; foreach (KeyValuePair getter in getters) { if (getter.Value != null) { obj.Add(this.MapClrMemberNameToJsonFieldName(getter.Key), getter.Value(input)); } } output = obj; return true; } } #if SIMPLE_JSON_DATACONTRACT [GeneratedCode("simple-json", "1.0.0")] #if SIMPLE_JSON_INTERNAL internal #else public #endif class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy { public DataContractJsonSerializerStrategy() { GetCache = new ReflectionUtils.ThreadSafeDictionary>(GetterValueFactory); SetCache = new ReflectionUtils.ThreadSafeDictionary>>(SetterValueFactory); } internal override IDictionary GetterValueFactory(Type type) { bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null; if (!hasDataContract) return base.GetterValueFactory(type); string jsonKey; IDictionary result = new Dictionary(); foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type)) { if (propertyInfo.CanRead) { MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo); if (!getMethod.IsStatic && CanAdd(propertyInfo, out jsonKey)) result[jsonKey] = ReflectionUtils.GetGetMethod(propertyInfo); } } foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type)) { if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey)) result[jsonKey] = ReflectionUtils.GetGetMethod(fieldInfo); } return result; } internal override IDictionary> SetterValueFactory(Type type) { bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null; if (!hasDataContract) return base.SetterValueFactory(type); string jsonKey; IDictionary> result = new Dictionary>(); foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type)) { if (propertyInfo.CanWrite) { MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo); if (!setMethod.IsStatic && CanAdd(propertyInfo, out jsonKey)) result[jsonKey] = new KeyValuePair(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo)); } } foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type)) { if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey)) result[jsonKey] = new KeyValuePair(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo)); } // todo implement sorting for DATACONTRACT. return result; } private static bool CanAdd(MemberInfo info, out string jsonKey) { jsonKey = null; if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null) return false; DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute)); if (dataMemberAttribute == null) return false; jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name; return true; } } #endif namespace Reflection { // This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules // that might be in place in the target project. [GeneratedCode("reflection-utils", "1.0.0")] #if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC public #else internal #endif class ReflectionUtils { private static readonly object[] EmptyObjects = new object[] { }; public delegate object GetDelegate(object source); public delegate void SetDelegate(object source, object value); public delegate object ConstructorDelegate(params object[] args); public delegate TValue ThreadSafeDictionaryValueFactory(TKey key); #if SIMPLE_JSON_TYPEINFO public static TypeInfo GetTypeInfo(Type type) { return type.GetTypeInfo(); } #else public static Type GetTypeInfo(Type type) { return type; } #endif public static Attribute GetAttribute(MemberInfo info, Type type) { #if SIMPLE_JSON_TYPEINFO if (info == null || type == null || !info.IsDefined(type)) return null; return info.GetCustomAttribute(type); #else if (info == null || type == null || !Attribute.IsDefined(info, type)) { return null; } return Attribute.GetCustomAttribute(info, type); #endif } public static Type GetGenericListElementType(Type type) { IEnumerable interfaces; #if SIMPLE_JSON_TYPEINFO interfaces = type.GetTypeInfo().ImplementedInterfaces; #else interfaces = type.GetInterfaces(); #endif foreach (Type implementedInterface in interfaces) { if (ReflectionUtils.IsTypeGeneric(implementedInterface) && implementedInterface.GetGenericTypeDefinition() == typeof(IList<>)) { return ReflectionUtils.GetGenericTypeArguments(implementedInterface)[0]; } } return ReflectionUtils.GetGenericTypeArguments(type)[0]; } public static Attribute GetAttribute(Type objectType, Type attributeType) { #if SIMPLE_JSON_TYPEINFO if (objectType == null || attributeType == null || !objectType.GetTypeInfo().IsDefined(attributeType)) return null; return objectType.GetTypeInfo().GetCustomAttribute(attributeType); #else if (objectType == null || attributeType == null || !Attribute.IsDefined(objectType, attributeType)) { return null; } return Attribute.GetCustomAttribute(objectType, attributeType); #endif } public static Type[] GetGenericTypeArguments(Type type) { #if SIMPLE_JSON_TYPEINFO return type.GetTypeInfo().GenericTypeArguments; #else return type.GetGenericArguments(); #endif } public static bool IsTypeGeneric(Type type) { return ReflectionUtils.GetTypeInfo(type) .IsGenericType; } public static bool IsTypeGenericeCollectionInterface(Type type) { if (!ReflectionUtils.IsTypeGeneric(type)) { return false; } Type genericDefinition = type.GetGenericTypeDefinition(); return genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>); } public static bool IsAssignableFrom(Type type1, Type type2) { return ReflectionUtils.GetTypeInfo(type1) .IsAssignableFrom(ReflectionUtils.GetTypeInfo(type2)); } public static bool IsTypeDictionary(Type type) { #if SIMPLE_JSON_TYPEINFO if (typeof(IDictionary<,>).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) return true; #else if (typeof(System.Collections.IDictionary).IsAssignableFrom(type)) { return true; } #endif if (!ReflectionUtils.GetTypeInfo(type) .IsGenericType) { return false; } Type genericDefinition = type.GetGenericTypeDefinition(); return genericDefinition == typeof(IDictionary<,>); } public static bool IsNullableType(Type type) { return ReflectionUtils.GetTypeInfo(type) .IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } public static object ToNullableType(object obj, Type nullableType) { return obj == null ? null : Convert.ChangeType(obj, Nullable.GetUnderlyingType(nullableType), CultureInfo.InvariantCulture); } public static bool IsValueType(Type type) { return ReflectionUtils.GetTypeInfo(type) .IsValueType; } public static IEnumerable GetConstructors(Type type) { #if SIMPLE_JSON_TYPEINFO return type.GetTypeInfo().DeclaredConstructors; #else return type.GetConstructors(); #endif } public static ConstructorInfo GetConstructorInfo(Type type, params Type[] argsType) { IEnumerable constructorInfos = ReflectionUtils.GetConstructors(type); int i; bool matches; foreach (ConstructorInfo constructorInfo in constructorInfos) { ParameterInfo[] parameters = constructorInfo.GetParameters(); if (argsType.Length != parameters.Length) { continue; } i = 0; matches = true; foreach (ParameterInfo parameterInfo in constructorInfo.GetParameters()) { if (parameterInfo.ParameterType != argsType[i]) { matches = false; break; } } if (matches) { return constructorInfo; } } return null; } public static IEnumerable GetProperties(Type type) { #if SIMPLE_JSON_TYPEINFO return type.GetRuntimeProperties(); #else return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); #endif } public static IEnumerable GetFields(Type type) { #if SIMPLE_JSON_TYPEINFO return type.GetRuntimeFields(); #else return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); #endif } public static MethodInfo GetGetterMethodInfo(PropertyInfo propertyInfo) { #if SIMPLE_JSON_TYPEINFO return propertyInfo.GetMethod; #else return propertyInfo.GetGetMethod(true); #endif } public static MethodInfo GetSetterMethodInfo(PropertyInfo propertyInfo) { #if SIMPLE_JSON_TYPEINFO return propertyInfo.SetMethod; #else return propertyInfo.GetSetMethod(true); #endif } public static ConstructorDelegate GetContructor(ConstructorInfo constructorInfo) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetConstructorByReflection(constructorInfo); #else return ReflectionUtils.GetConstructorByExpression(constructorInfo); #endif } public static ConstructorDelegate GetContructor(Type type, params Type[] argsType) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetConstructorByReflection(type, argsType); #else return ReflectionUtils.GetConstructorByExpression(type, argsType); #endif } public static ConstructorDelegate GetConstructorByReflection(ConstructorInfo constructorInfo) { return delegate(object[] args) { return constructorInfo.Invoke(args); }; } public static ConstructorDelegate GetConstructorByReflection(Type type, params Type[] argsType) { ConstructorInfo constructorInfo = ReflectionUtils.GetConstructorInfo(type, argsType); return constructorInfo == null ? null : ReflectionUtils.GetConstructorByReflection(constructorInfo); } #if !SIMPLE_JSON_NO_LINQ_EXPRESSION public static ConstructorDelegate GetConstructorByExpression(ConstructorInfo constructorInfo) { ParameterInfo[] paramsInfo = constructorInfo.GetParameters(); ParameterExpression param = Expression.Parameter(typeof(object[]), "args"); Expression[] argsExp = new Expression[paramsInfo.Length]; for (int i = 0; i < paramsInfo.Length; i++) { Expression index = Expression.Constant(i); Type paramType = paramsInfo[i] .ParameterType; Expression paramAccessorExp = Expression.ArrayIndex(param, index); Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType); argsExp[i] = paramCastExp; } NewExpression newExp = Expression.New(constructorInfo, argsExp); Expression> lambda = Expression.Lambda>(newExp, param); Func compiledLambda = lambda.Compile(); return delegate(object[] args) { return compiledLambda(args); }; } public static ConstructorDelegate GetConstructorByExpression(Type type, params Type[] argsType) { ConstructorInfo constructorInfo = ReflectionUtils.GetConstructorInfo(type, argsType); return constructorInfo == null ? null : ReflectionUtils.GetConstructorByExpression(constructorInfo); } #endif public static GetDelegate GetGetMethod(PropertyInfo propertyInfo) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetGetMethodByReflection(propertyInfo); #else return ReflectionUtils.GetGetMethodByExpression(propertyInfo); #endif } public static GetDelegate GetGetMethod(FieldInfo fieldInfo) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetGetMethodByReflection(fieldInfo); #else return ReflectionUtils.GetGetMethodByExpression(fieldInfo); #endif } public static GetDelegate GetGetMethodByReflection(PropertyInfo propertyInfo) { MethodInfo methodInfo = ReflectionUtils.GetGetterMethodInfo(propertyInfo); return delegate(object source) { return methodInfo.Invoke(source, ReflectionUtils.EmptyObjects); }; } public static GetDelegate GetGetMethodByReflection(FieldInfo fieldInfo) { return delegate(object source) { return fieldInfo.GetValue(source); }; } #if !SIMPLE_JSON_NO_LINQ_EXPRESSION public static GetDelegate GetGetMethodByExpression(PropertyInfo propertyInfo) { MethodInfo getMethodInfo = ReflectionUtils.GetGetterMethodInfo(propertyInfo); ParameterExpression instance = Expression.Parameter(typeof(object), "instance"); UnaryExpression instanceCast = !ReflectionUtils.IsValueType(propertyInfo.DeclaringType) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType); Func compiled = Expression.Lambda>(Expression.TypeAs(Expression.Call(instanceCast, getMethodInfo), typeof(object)), instance) .Compile(); return delegate(object source) { return compiled(source); }; } public static GetDelegate GetGetMethodByExpression(FieldInfo fieldInfo) { ParameterExpression instance = Expression.Parameter(typeof(object), "instance"); MemberExpression member = Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo); GetDelegate compiled = Expression.Lambda(Expression.Convert(member, typeof(object)), instance) .Compile(); return delegate(object source) { return compiled(source); }; } #endif public static SetDelegate GetSetMethod(PropertyInfo propertyInfo) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetSetMethodByReflection(propertyInfo); #else return ReflectionUtils.GetSetMethodByExpression(propertyInfo); #endif } public static SetDelegate GetSetMethod(FieldInfo fieldInfo) { #if SIMPLE_JSON_NO_LINQ_EXPRESSION return ReflectionUtils.GetSetMethodByReflection(fieldInfo); #else return ReflectionUtils.GetSetMethodByExpression(fieldInfo); #endif } public static SetDelegate GetSetMethodByReflection(PropertyInfo propertyInfo) { MethodInfo methodInfo = ReflectionUtils.GetSetterMethodInfo(propertyInfo); return delegate(object source, object value) { methodInfo.Invoke(source, new object[] {value}); }; } public static SetDelegate GetSetMethodByReflection(FieldInfo fieldInfo) { return delegate(object source, object value) { fieldInfo.SetValue(source, value); }; } #if !SIMPLE_JSON_NO_LINQ_EXPRESSION public static SetDelegate GetSetMethodByExpression(PropertyInfo propertyInfo) { MethodInfo setMethodInfo = ReflectionUtils.GetSetterMethodInfo(propertyInfo); ParameterExpression instance = Expression.Parameter(typeof(object), "instance"); ParameterExpression value = Expression.Parameter(typeof(object), "value"); UnaryExpression instanceCast = !ReflectionUtils.IsValueType(propertyInfo.DeclaringType) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType); UnaryExpression valueCast = !ReflectionUtils.IsValueType(propertyInfo.PropertyType) ? Expression.TypeAs(value, propertyInfo.PropertyType) : Expression.Convert(value, propertyInfo.PropertyType); Action compiled = Expression.Lambda>(Expression.Call(instanceCast, setMethodInfo, valueCast), new ParameterExpression[] {instance, value}) .Compile(); return delegate(object source, object val) { compiled(source, val); }; } public static SetDelegate GetSetMethodByExpression(FieldInfo fieldInfo) { ParameterExpression instance = Expression.Parameter(typeof(object), "instance"); ParameterExpression value = Expression.Parameter(typeof(object), "value"); Action compiled = Expression.Lambda>(ReflectionUtils.Assign(Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo), Expression.Convert(value, fieldInfo.FieldType)), instance, value) .Compile(); return delegate(object source, object val) { compiled(source, val); }; } public static BinaryExpression Assign(Expression left, Expression right) { #if SIMPLE_JSON_TYPEINFO return Expression.Assign(left, right); #else MethodInfo assign = typeof(Assigner<>).MakeGenericType(left.Type) .GetMethod("Assign"); BinaryExpression assignExpr = Expression.Add(left, right, assign); return assignExpr; #endif } private static class Assigner { #region Static Methods public static T Assign(ref T left, T right) { return left = right; } #endregion } #endif public sealed class ThreadSafeDictionary : IDictionary { #region Constructors public ThreadSafeDictionary(ThreadSafeDictionaryValueFactory valueFactory) { _valueFactory = valueFactory; } #endregion #region Fields private Dictionary _dictionary; private readonly object _lock = new object(); private readonly ThreadSafeDictionaryValueFactory _valueFactory; #endregion #region Properties public int Count { get { return _dictionary.Count; } } public bool IsReadOnly { get { throw new NotImplementedException(); } } public TValue this[TKey key] { get { return Get(key); } set { throw new NotImplementedException(); } } public ICollection Keys { get { return _dictionary.Keys; } } public ICollection Values { get { return _dictionary.Values; } } #endregion #region Methods public void Add(TKey key, TValue value) { throw new NotImplementedException(); } public void Add(KeyValuePair item) { throw new NotImplementedException(); } private TValue AddValue(TKey key) { TValue value = _valueFactory(key); lock (_lock) { if (_dictionary == null) { _dictionary = new Dictionary(); _dictionary[key] = value; } else { TValue val; if (_dictionary.TryGetValue(key, out val)) { return val; } Dictionary dict = new Dictionary(_dictionary); dict[key] = value; _dictionary = dict; } } return value; } public void Clear() { throw new NotImplementedException(); } public bool Contains(KeyValuePair item) { throw new NotImplementedException(); } public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { throw new NotImplementedException(); } private TValue Get(TKey key) { if (_dictionary == null) { return this.AddValue(key); } TValue value; if (!_dictionary.TryGetValue(key, out value)) { return this.AddValue(key); } return value; } public IEnumerator> GetEnumerator() { return _dictionary.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); } public bool Remove(TKey key) { throw new NotImplementedException(); } public bool Remove(KeyValuePair item) { throw new NotImplementedException(); } public bool TryGetValue(TKey key, out TValue value) { value = this[key]; return true; } #endregion } } } } // ReSharper restore LoopCanBeConvertedToQuery // ReSharper restore RedundantExplicitArrayCreation // ReSharper restore SuggestUseVarKeywordEvident