Esempio n. 1
0
        internal JsonClassInfo(Type type, JsonSerializerOptions options)
        {
            Type      = type;
            ClassType = GetClassType(type, options);

            CreateObject = options.ClassMaterializerStrategy.CreateConstructor(type);

            // Ignore properties on enumerable.
            switch (ClassType)
            {
            case ClassType.Object:
            {
                var propertyNames = new HashSet <string>(StringComparer.Ordinal);

                foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    // Ignore indexers
                    if (propertyInfo.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    // For now we only support public getters\setters
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);

                        Debug.Assert(jsonPropertyInfo.NameUsedToCompareAsString != null);

                        // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
                        if (!propertyNames.Add(jsonPropertyInfo.NameUsedToCompareAsString))
                        {
                            ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo);
                        }

                        jsonPropertyInfo.ClearUnusedValuesAfterAdd();
                    }
                }

                DetermineExtensionDataProperty();
            }
            break;

            case ClassType.Enumerable:
            case ClassType.Dictionary:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                JsonPropertyInfo policyProperty = AddPolicyProperty(type, options);

                // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary).
                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(policyProperty.RuntimePropertyType);

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.IDictionaryConstructible:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);

                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(
                    typeof(Dictionary <,>).MakeGenericType(typeof(string), elementType));

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.Value:
            case ClassType.Unknown:
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);
                break;

            default:
                Debug.Fail($"Unexpected class type: {ClassType}");
                break;
            }
        }
Esempio n. 2
0
        internal JsonClassInfo(Type type, JsonSerializerOptions options)
        {
            Type      = type;
            ClassType = GetClassType(type);

            CreateObject = options.ClassMaterializerStrategy.CreateConstructor(type);

            // Ignore properties on enumerable.
            switch (ClassType)
            {
            case ClassType.Object:
            {
                var propertyNames = new HashSet <string>(StringComparer.Ordinal);

                foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    // Ignore indexers
                    if (propertyInfo.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    // For now we only support public getters\setters
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);

                        Debug.Assert(jsonPropertyInfo.NameUsedToCompareAsString != null);

                        // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
                        if (!propertyNames.Add(jsonPropertyInfo.NameUsedToCompareAsString))
                        {
                            ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo);
                        }

                        jsonPropertyInfo.ClearUnusedValuesAfterAdd();
                    }
                }

                DetermineExtensionDataProperty();
            }
            break;

            case ClassType.Enumerable:
            case ClassType.Dictionary:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                JsonPropertyInfo policyProperty = AddPolicyProperty(type, options);

                // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary).
                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(policyProperty.RuntimePropertyType);

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                Type elementType = GetElementType(type, parentType: null, memberInfo: null);
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.IDictionaryConstructible:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                Type elementType = GetElementType(type, parentType: null, memberInfo: null);

                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(
                    typeof(Dictionary <,>).MakeGenericType(typeof(string), elementType));

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            // TODO: Utilize converter mechanism to handle (de)serialization of KeyValuePair
            // when it goes through: https://github.com/dotnet/corefx/issues/36639.
            case ClassType.KeyValuePair:
            {
                // For deserialization, we treat it as ClassType.IDictionaryConstructible so we can parse it like a dictionary
                // before using converter-like logic to create a KeyValuePair instance.

                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                Type elementType = GetElementType(type, parentType: null, memberInfo: null);

                // Make this Dictionary<string, object> to accomodate input of form {"Key": "MyKey", "Value": 1}.
                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(typeof(Dictionary <string, object>));

                // Create a ClassInfo that maps to the element type which is used for deserialization and policies.
                ElementClassInfo = options.GetOrAddClass(elementType);

                // For serialization, we treat it like ClassType.Object to utilize the public getters.

                // Add Key property
                PropertyInfo     propertyInfo     = type.GetProperty("Key", BindingFlags.Public | BindingFlags.Instance);
                JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);
                Debug.Assert(jsonPropertyInfo.NameUsedToCompareAsString != null);
                jsonPropertyInfo.ClearUnusedValuesAfterAdd();

                // Add Value property.
                propertyInfo     = type.GetProperty("Value", BindingFlags.Public | BindingFlags.Instance);
                jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);
                Debug.Assert(jsonPropertyInfo.NameUsedToCompareAsString != null);
                jsonPropertyInfo.ClearUnusedValuesAfterAdd();
            }
            break;

            case ClassType.Value:
            case ClassType.Unknown:
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);
                break;

            default:
                Debug.Fail($"Unexpected class type: {ClassType}");
                break;
            }
        }