示例#1
0
        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);
        }
示例#2
0
文件: JSON.cs 项目: micbil/TinyJSON
        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);
        }
示例#3
0
        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);
        }
示例#4
0
        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);
        }