private static T DecodeType <T>(Variant data) { var type = typeof(T); if (type.IsEnum) { return((T)Enum.Parse(type, data.ToString())); } if (type.IsPrimitive || type == typeof(string)) { return((T)Convert.ChangeType(data, type)); } if (type.IsArray) { var makeFunc = decodeArrayMethod.MakeGenericMethod(new Type[] { type.GetElementType() }); return((T)makeFunc.Invoke(null, new object[] { data })); } if (typeof(IList).IsAssignableFrom(type)) { var makeFunc = decodeListMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } if (typeof(IDictionary).IsAssignableFrom(type)) { var makeFunc = decodeDictionaryMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } // This is a class or struct, so instantiate it with the default constructor. var instance = Activator.CreateInstance <T>(); // Now decode each field, except for those tagged with [Skip] attribute. foreach (var pair in data as ProxyObject) { var field = type.GetField(pair.Key, instanceBindingFlags); if (field != null) { if (!Attribute.GetCustomAttributes(field).Any(attr => attr is Skip)) { var makeFunc = decodeTypeMethod.MakeGenericMethod(new Type[] { field.FieldType }); if (type.IsValueType) { // Type is a struct var instanceRef = (object)instance; field.SetValue(instanceRef, makeFunc.Invoke(null, new object[] { pair.Value })); instance = (T)instanceRef; } else { // Type is a class field.SetValue(instance, makeFunc.Invoke(null, new object[] { pair.Value })); } } } } // Invoke methods tagged with [Load] attribute. foreach (var method in type.GetMethods(instanceBindingFlags)) { if (method.GetCustomAttributes(false).Any(attr => attr is Load)) { if (method.GetParameters().Length == 0) { method.Invoke(instance, null); } else { method.Invoke(instance, new object[] { data }); } } } return(instance); }
private static T DecodeType <T>(Variant data) { if (data == null) { return(default(T)); } Type type = typeof(T); #if NETCORE TypeInfo tInfo = type.GetTypeInfo(); #endif #if !NETCORE if (type.IsEnum) #else if (tInfo.IsEnum) #endif { return((T)Enum.Parse(type, data.ToString())); } #if !NETCORE if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal)) #else if (tInfo.IsPrimitive || type == typeof(string) || type == typeof(decimal)) #endif { return((T)Convert.ChangeType(data, type)); } if (type.IsArray) { if (type.GetArrayRank() == 1) { var makeFunc = decodeArrayMethod.MakeGenericMethod(new Type[] { type.GetElementType() }); return((T)makeFunc.Invoke(null, new object[] { data })); } else { var arrayData = data as ProxyArray; var arrayRank = type.GetArrayRank(); var rankLengths = new int[arrayRank]; if (arrayData.CanBeMultiRankArray(rankLengths)) { var array = Array.CreateInstance(type.GetElementType(), rankLengths); var makeFunc = decodeMultiRankArrayMethod.MakeGenericMethod(new Type[] { type.GetElementType() }); try { makeFunc.Invoke(null, new object[] { arrayData, array, 1, rankLengths }); } catch (Exception e) { throw new DecodeException("Error decoding multidimensional array. Did you try to decode into an array of incompatible rank or element type?", e); } return((T)Convert.ChangeType(array, typeof(T))); } throw new DecodeException("Error decoding multidimensional array; JSON data doesn't seem fit this structure."); #pragma warning disable 0162 return(default(T)); #pragma warning restore 0162 } } //#if !NETCORE if (typeof(IList).IsAssignableFrom(type)) { var makeFunc = decodeListMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } //#else // if (typeof(IList).GetTypeInfo().IsAssignableFrom(type)) // { // var makeFunc = decodeListMethod.MakeGenericMethod(tInfo.GetGenericArguments()); // return (T)makeFunc.Invoke(null, new object[] { data }); // } //#endif //#if !NETCORE if (typeof(IDictionary).IsAssignableFrom(type)) { var makeFunc = decodeDictionaryMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } //#else // if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(type)) // { // var makeFunc = decodeDictionaryMethod.MakeGenericMethod(tInfo.GetGenericArguments()); // return (T)makeFunc.Invoke(null, new object[] { data }); // } //#endif //we need to handle HashSet's differently because there does not exist a nongeneric interface for them if (data is ProxyArray && (data as ProxyArray).Count > 0) { var makeFunc = decodeHashSetMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } // At this point we should be dealing with a class or struct. T instance; var proxyObject = data as ProxyObject; if (proxyObject == null) { throw new InvalidCastException("ProxyObject expected when decoding into '" + type.FullName + "'."); } // If there's a type hint, use it to create the instance. var typeHint = proxyObject.TypeHint; if (typeHint != null && typeHint != type.FullName) { var makeType = FindType(typeHint); if (makeType == null) { throw new TypeLoadException("Could not load type '" + typeHint + "'."); } else { if (type.IsAssignableFrom(makeType)) { #if !NETCORE instance = (T)Activator.CreateInstance(makeType, nonPublic: true); #else instance = (T)Activator.CreateInstance(makeType); #endif type = makeType; } else { throw new InvalidCastException("Cannot assign type '" + typeHint + "' to type '" + type.FullName + "'."); } } } else { #if !NETCORE // We don't have a type hint, so just instantiate the type we have. instance = (T)Activator.CreateInstance(typeof(T), nonPublic: true); #else // We don't have a type hint, so just instantiate the type we have. instance = (T)Activator.CreateInstance(typeof(T)); #endif } List <MemberInfo> members = new List <MemberInfo>(); //#if !NETCORE members.AddRange(type.GetProperties(JSON.INSTANCE_BINDING_FLAGS)); members.AddRange(type.GetFields(JSON.INSTANCE_BINDING_FLAGS)); //#else // members.AddRange(tInfo.GetProperties(JSON.INSTANCE_BINDING_FLAGS)); // members.AddRange(tInfo.GetFields(JSON.INSTANCE_BINDING_FLAGS)); //#endif for (int i = 0; i < members.Count; i++) { MemberInfo member = members[i]; FieldInfo fieldInfo = null; PropertyInfo propertyInfo = null; string memberName = member.Name; int shouldEncode = -1; #if !NETCORE Attribute[] attributes = Attribute.GetCustomAttributes(member, inherit: true); #else IEnumerable attributes = member.GetCustomAttributes(true); #endif foreach (var att in attributes) { if (att is ExcludeAttribute) { shouldEncode = 0; break; } if (att is IncludeAttribute) { shouldEncode = 1; continue; } if (att is AliasAttribute) { memberName = ((AliasAttribute)att).alias; continue; } } //We only want to encode the member if we have the key. if (proxyObject.ContainsKey(memberName)) { MethodInfo MakeMethod = null; if (member is FieldInfo) { fieldInfo = member as FieldInfo; if (shouldEncode == -1) { //This only happens if no attribute was found that modifies if it should be encoded or not. if (fieldInfo.IsPublic) { shouldEncode = 1; } } if (shouldEncode == 1) { //We are going to encode this field MakeMethod = decodeTypeMethod.MakeGenericMethod(new Type[] { fieldInfo.FieldType }); #if !NETCORE if (type.IsValueType) #else if (tInfo.IsValueType) #endif { object instanceRef = (object)instance; fieldInfo.SetValue(instanceRef, MakeMethod.Invoke(obj: null, parameters: new object[] { proxyObject[memberName] })); instance = (T)instanceRef; } else { fieldInfo.SetValue(instance, MakeMethod.Invoke(null, new object[] { proxyObject[memberName] })); } } } else if (member is PropertyInfo) { propertyInfo = member as PropertyInfo; if (shouldEncode == 1 && propertyInfo.CanWrite) { //We are going to encode this property MakeMethod = decodeTypeMethod.MakeGenericMethod(new Type[] { propertyInfo.PropertyType }); #if !NETCORE if (type.IsValueType) #else if (tInfo.IsValueType) #endif { object instanceRef = (object)instance; propertyInfo.SetValue(instanceRef, MakeMethod.Invoke(obj: null, parameters: new object[] { proxyObject[memberName] }), null); instance = (T)instanceRef; } else { propertyInfo.SetValue(instance, MakeMethod.Invoke(obj: null, parameters: new object[] { proxyObject[memberName] }), null); } } } } } //#if !NETCORE // Invoke methods tagged with [AfterDecode] attribute. foreach (var method in type.GetMethods(instanceBindingFlags)) //#else // foreach (var method in tInfo.GetMethods(instanceBindingFlags)) //#endif { if (method.GetCustomAttributes(false).AnyOfType(typeof(AfterDecodeAttribute))) { if (method.GetParameters().Length == 0) { method.Invoke(instance, null); } else { method.Invoke(instance, new object[] { data }); } } } return(instance); }
private static T DecodeType <T>(Variant data) { if (data == null) { return(default(T)); } var type = typeof(T); if (type.IsEnum) { return((T)Enum.Parse(type, data.ToString())); } if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal)) { return((T)Convert.ChangeType(data, type)); } if (type.IsArray) { if (type.GetArrayRank() == 1) { var makeFunc = decodeArrayMethod.MakeGenericMethod(new Type[] { type.GetElementType() }); return((T)makeFunc.Invoke(null, new object[] { data })); } else { var arrayData = data as ProxyArray; var arrayRank = type.GetArrayRank(); var rankLengths = new int[arrayRank]; if (arrayData.CanBeMultiRankArray(rankLengths)) { var array = Array.CreateInstance(type.GetElementType(), rankLengths); var makeFunc = decodeMultiRankArrayMethod.MakeGenericMethod(new Type[] { type.GetElementType() }); try { makeFunc.Invoke(null, new object[] { arrayData, array, 1, rankLengths }); } catch (Exception e) { throw new DecodeException("Error decoding multidimensional array. Did you try to decode into an array of incompatible rank or element type?", e); } return((T)Convert.ChangeType(array, typeof(T))); } throw new DecodeException("Error decoding multidimensional array; JSON data doesn't seem fit this structure."); #pragma warning disable 0162 return(default(T)); #pragma warning restore 0162 } } if (typeof(IList).IsAssignableFrom(type)) { var makeFunc = decodeListMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } if (typeof(IDictionary).IsAssignableFrom(type)) { var makeFunc = decodeDictionaryMethod.MakeGenericMethod(type.GetGenericArguments()); return((T)makeFunc.Invoke(null, new object[] { data })); } // At this point we should be dealing with a class or struct. T instance; var proxyObject = data as ProxyObject; if (proxyObject == null) { throw new InvalidCastException("ProxyObject expected when decoding into '" + type.FullName + "'."); } // If there's a type hint, use it to create the instance. var typeHint = proxyObject.TypeHint; if (typeHint != null && typeHint != type.FullName) { var makeType = FindType(typeHint); if (makeType == null) { throw new TypeLoadException("Could not load type '" + typeHint + "'."); } else { if (type.IsAssignableFrom(makeType)) { instance = (T)Activator.CreateInstance(makeType); type = makeType; } else { throw new InvalidCastException("Cannot assign type '" + typeHint + "' to type '" + type.FullName + "'."); } } } else { // We don't have a type hint, so just instantiate the type we have. instance = Activator.CreateInstance <T>(); } // Now decode fields and properties. foreach (var pair in data as ProxyObject) { var field = type.GetField(pair.Key, instanceBindingFlags); if (field != null) { var shouldDecode = field.IsPublic; foreach (var attribute in field.GetCustomAttributes(true)) { if (excludeAttrType.IsAssignableFrom(attribute.GetType())) { shouldDecode = false; } if (includeAttrType.IsAssignableFrom(attribute.GetType())) { shouldDecode = true; } } if (shouldDecode) { var makeFunc = decodeTypeMethod.MakeGenericMethod(new Type[] { field.FieldType }); if (type.IsValueType) { // Type is a struct. var instanceRef = (object)instance; field.SetValue(instanceRef, makeFunc.Invoke(null, new object[] { pair.Value })); instance = (T)instanceRef; } else { // Type is a class. field.SetValue(instance, makeFunc.Invoke(null, new object[] { pair.Value })); } } } var property = type.GetProperty(pair.Key, instanceBindingFlags); if (property != null) { if (property.CanWrite && property.GetCustomAttributes(false).AnyOfType(includeAttrType)) { var makeFunc = decodeTypeMethod.MakeGenericMethod(new Type[] { property.PropertyType }); if (type.IsValueType) { // Type is a struct. var instanceRef = (object)instance; property.SetValue(instanceRef, makeFunc.Invoke(null, new object[] { pair.Value }), null); instance = (T)instanceRef; } else { // Type is a class. property.SetValue(instance, makeFunc.Invoke(null, new object[] { pair.Value }), null); } } } } // Invoke methods tagged with [AfterDecode] attribute. foreach (var method in type.GetMethods(instanceBindingFlags)) { if (method.GetCustomAttributes(false).AnyOfType(typeof(AfterDecode))) { if (method.GetParameters().Length == 0) { method.Invoke(instance, null); } else { method.Invoke(instance, new object[] { data }); } } } return(instance); }
static T DecodeType <T>(Variant data) { if (data == null) { return(default(T)); } var type = typeof(T); if (type.IsEnum) { return((T)Enum.Parse(type, data.ToString(CultureInfo.InvariantCulture))); } if (type.IsPrimitive || type == typeof(string) || type == typeof(char) || type == typeof(decimal) || type == typeof(DateTime) #if UNITY_ENGINE || type == typeof(Color) || type == typeof(Color32) #endif ) { return((T)Convert.ChangeType(data, type)); } if (type.IsArray) { if (type.GetArrayRank() == 1) { var makeFunc = decodeArrayMethod.MakeGenericMethod(type.GetElementType()); return((T)makeFunc.Invoke(null, new object[] { data })); } var arrayData = data as ProxyArray; if (arrayData == null) { throw new DecodeException("Variant is expected to be a ProxyArray here, but it is not."); } var arrayRank = type.GetArrayRank(); var rankLengths = new int[arrayRank]; if (arrayData.CanBeMultiRankArray(rankLengths)) { var elementType = type.GetElementType(); if (elementType == null) { throw new DecodeException("Array element type is expected to be not null, but it is."); } var array = Array.CreateInstance(elementType, rankLengths); var makeFunc = decodeMultiRankArrayMethod.MakeGenericMethod(elementType); try { makeFunc.Invoke(null, new object[] { arrayData, array, 1, rankLengths }); } catch (Exception e) { throw new DecodeException("Error decoding multidimensional array. Did you try to decode into an array of incompatible rank or element type?", e); } return((T)Convert.ChangeType(array, typeof(T))); } throw new DecodeException("Error decoding multidimensional array; JSON data doesn't seem fit this structure."); } if (typeof(IList).IsAssignableFrom(type)) { List <Type> typeArguments = new List <Type> { type }; typeArguments.AddRange(type.GetGenericArguments()); var makeFunc = decodeListMethod.MakeGenericMethod(typeArguments.ToArray()); return((T)makeFunc.Invoke(null, new object[] { data })); } if (typeof(IDictionary).IsAssignableFrom(type)) { List <Type> typeArguments = new List <Type> { type }; typeArguments.AddRange(type.GetGenericArguments()); var makeFunc = decodeDictionaryMethod.MakeGenericMethod(typeArguments.ToArray()); return((T)makeFunc.Invoke(null, new object[] { data })); } // At this point we should be dealing with a class or struct. T instance; var proxyObject = data as ProxyObject; if (proxyObject == null) { throw new InvalidCastException("ProxyObject expected when decoding into '" + type.FullName + "'."); } // If there's a type hint, use it to create the instance. var typeHint = proxyObject.TypeHint; if (typeHint != null && typeHint != type.FullName) { var makeType = FindType(typeHint); if (makeType == null) { throw new TypeLoadException("Could not load type '" + typeHint + "'."); } if (type.IsAssignableFrom(makeType)) { instance = (T)Activator.CreateInstance(makeType); type = makeType; } else { throw new InvalidCastException("Cannot assign type '" + typeHint + "' to type '" + type.FullName + "'."); } } else { // We don't have a type hint, so just instantiate the type we have. instance = Activator.CreateInstance <T>(); } // Now decode fields and properties. foreach (var pair in (ProxyObject)data) { var field = type.GetField(pair.Key, instanceBindingFlags); // If the field doesn't exist or is excluded, search for an [EncodeName] or any [DecodeAlias] if (field == null || Attribute.IsDefined(field, typeof(Exclude))) { foreach (var fieldInfo in type.GetFields(instanceBindingFlags)) { foreach (var attribute in fieldInfo.GetCustomAttributes(true)) { if (encodeNameAttrType.IsInstanceOfType(attribute)) { if (((EncodeName)attribute).Name == pair.Key) { field = fieldInfo; break; } } if (decodeAliasAttrType.IsInstanceOfType(attribute)) { if (((DecodeAlias)attribute).Contains(pair.Key)) { field = fieldInfo; break; } } } } } if (field != null) { var shouldDecode = field.IsPublic; foreach (var attribute in field.GetCustomAttributes(true)) { if (excludeAttrType.IsInstanceOfType(attribute)) { shouldDecode = false; } if (includeAttrType.IsInstanceOfType(attribute)) { shouldDecode = true; } } if (shouldDecode) { var makeFunc = decodeTypeMethod.MakeGenericMethod(field.FieldType); if (type.IsValueType) { // Type is a struct. var instanceRef = (object)instance; field.SetValue(instanceRef, makeFunc.Invoke(null, new object[] { pair.Value })); instance = (T)instanceRef; } else { // Type is a class. field.SetValue(instance, makeFunc.Invoke(null, new object[] { pair.Value })); } } } var property = type.GetProperty(pair.Key, instanceBindingFlags); // If the property doesn't exist or is excluded, search for an [EncodeName] or any [DecodeAlias] if (property == null || Attribute.IsDefined(property, typeof(Exclude))) { foreach (var propertyInfo in type.GetProperties(instanceBindingFlags)) { foreach (var attribute in propertyInfo.GetCustomAttributes(false)) { if (encodeNameAttrType.IsInstanceOfType(attribute)) { if (((EncodeName)attribute).Name == pair.Key) { property = propertyInfo; break; } } if (decodeAliasAttrType.IsInstanceOfType(attribute)) { if (((DecodeAlias)attribute).Contains(pair.Key)) { property = propertyInfo; break; } } } } } if (property != null) { if (property.CanWrite && property.GetCustomAttributes(false).AnyOfType(includeAttrType)) { var makeFunc = decodeTypeMethod.MakeGenericMethod(new Type[] { property.PropertyType }); if (type.IsValueType) { // Type is a struct. var instanceRef = (object)instance; property.SetValue(instanceRef, makeFunc.Invoke(null, new object[] { pair.Value }), null); instance = (T)instanceRef; } else { // Type is a class. property.SetValue(instance, makeFunc.Invoke(null, new object[] { pair.Value }), null); } } } } // Invoke methods tagged with [AfterDecode] attribute. foreach (var method in type.GetMethods(instanceBindingFlags)) { if (Attribute.IsDefined(method, typeof(AfterDecode))) { method.Invoke(instance, method.GetParameters().Length == 0 ? null : new object[] { data }); } } return(instance); }