示例#1
0
        /// <summary>
        /// Create a new type support
        /// </summary>
        /// <param name="type">The type to analyze</param>
        /// <param name="options">The type support inspection options</param>
        public ExtendedType(Type type, TypeSupportOptions options)
        {
            Type                 = type ?? throw new ArgumentNullException();
            Attributes           = new List <Type>();
            Interfaces           = new List <Type>();
            GenericArgumentTypes = new List <Type>();
            KnownConcreteTypes   = new List <Type>();
            EnumValues           = new List <KeyValuePair <object, string> >();
            Properties           = new List <ExtendedProperty>();
            Fields               = new List <ExtendedField>();
            Constructors         = new List <ConstructorInfo>();
            EmptyConstructors    = new List <ConstructorInfo>();

            var isCachingSupported = options.BitwiseHasFlag(TypeSupportOptions.Caching);

            // if the type is cached, use it
            if (isCachingSupported && ExtendedTypeCache.Contains(type, options))
            {
                InitializeFromCache(ExtendedTypeCache.Get(type, options));
            }
            else
            {
                // inspect the type with the given options
                var typeInspector = new TypeInspector(this, options);
                typeInspector.Inspect();
                if (isCachingSupported)
                {
                    ExtendedTypeCache.CacheType(this, options);
                }
            }
        }
示例#2
0
        private void InspectGenericType(ExtendedType extendedType, Type type, TypeSupportOptions options)
        {
            var genericTypeDefinition = type.GetGenericTypeDefinition();
            var args = type.GetGenericArguments();

            if (args?.Any() == true)
            {
                foreach (var arg in args)
                {
                    extendedType.GenericArgumentTypes.Add(arg);
                }
            }

            if (options.BitwiseHasFlag(TypeSupportOptions.Collections))
            {
                if (typeof(ICollection).IsAssignableFrom(genericTypeDefinition) ||
                    typeof(IList) == type ||
                    typeof(IList).IsAssignableFrom(genericTypeDefinition) ||
                    typeof(IList <>).IsAssignableFrom(genericTypeDefinition) ||
                    typeof(ICollection <>).IsAssignableFrom(genericTypeDefinition) ||
                    typeof(Collection <>).IsAssignableFrom(genericTypeDefinition)
                    )
                {
                    extendedType.IsCollection = true;
                    extendedType.ElementType  = args.FirstOrDefault();
                    if (extendedType.ElementType != null)
                    {
                        extendedType.ElementNullableBaseType = GetNullableBaseType(extendedType.ElementType);
                    }
                }

                if (genericTypeDefinition == typeof(Dictionary <,>) ||
                    genericTypeDefinition == typeof(ConcurrentDictionary <,>) ||
                    genericTypeDefinition == typeof(IDictionary <,>))
                {
                    extendedType.IsDictionary = true;
                }
            }
            if (genericTypeDefinition == typeof(KeyValuePair <,>))
            {
                extendedType.IsKeyValuePair = true;
                extendedType.ElementType    = args.FirstOrDefault();
            }
        }
示例#3
0
        /// <summary>
        /// Inspect the extended type and populate its properties
        /// </summary>
        internal void Inspect()
        {
            if (_options.BitwiseHasFlag(TypeSupportOptions.Properties))
            {
                _extendedType.Properties = _extendedType.Type.GetProperties(PropertyOptions.All);
            }
            if (_options.BitwiseHasFlag(TypeSupportOptions.Fields))
            {
                _extendedType.Fields = _extendedType.Type.GetFields(FieldOptions.All);
            }
            if (_options.BitwiseHasFlag(TypeSupportOptions.Methods))
            {
                _extendedType.Methods = _extendedType.Type.GetMethods(MethodOptions.All);
            }

            if (_options.BitwiseHasFlag(TypeSupportOptions.Attributes))
            {
#if FEATURE_CUSTOM_ATTRIBUTES
                if (_extendedType.Type.CustomAttributes.Any())
                {
                    _extendedType.Attributes = _extendedType.Type.CustomAttributes.Select(x => x.AttributeType).ToList();
                }
#else
                // attributes
                if (_extendedType.Type.GetCustomAttributesData().Any())
                {
                    _extendedType.Attributes = _extendedType.Type.GetCustomAttributesData().Select(x => x.Constructor.DeclaringType).ToList();
                }
#endif
            }

            if (_options.BitwiseHasFlag(TypeSupportOptions.Constructors))
            {
                var             allConstructors         = _extendedType.Type.GetConstructors(ConstructorOptions.All);
                var             allEmptyConstructors    = allConstructors.Where(x => x.GetParameters().Any() == false).ToList();
                ConstructorInfo emptyConstructorDefined = null;
                emptyConstructorDefined               = _extendedType.Type.GetConstructor(Type.EmptyTypes);
                _extendedType.HasEmptyConstructor     = _extendedType.Type.IsValueType || emptyConstructorDefined != null;
                _extendedType.BaseHasEmptyConstructor = (_extendedType.Type.BaseType?.IsValueType == true || allEmptyConstructors?.Any() == true);
                _extendedType.Constructors            = allConstructors;
                _extendedType.EmptyConstructors       = allEmptyConstructors;
            }

            _extendedType.ConcreteType   = _extendedType.Type;
            _extendedType.IsAbstract     = _extendedType.Type.IsAbstract;
            _extendedType.IsSerializable = _extendedType.Type.IsSerializable;
            _extendedType.UnderlyingType = _extendedType.Type.UnderlyingSystemType;
            if (_extendedType.Type == typeof(string))
            {
                _extendedType.IsImmutable = true;
            }

            // collections support
            _extendedType.IsArray   = _extendedType.Type.IsArray;
            _extendedType.IsGeneric = _extendedType.Type.IsGenericType;
            if (_extendedType.IsArray)
            {
                _extendedType.ElementType = GetElementType(_extendedType.Type);
                if (_extendedType.ElementType != null)
                {
                    _extendedType.ElementNullableBaseType = GetNullableBaseType(_extendedType.ElementType);
                }
            }
            _extendedType.IsTuple         = _extendedType.Type.IsValueTupleType() || _extendedType.Type.IsTupleType();
            _extendedType.IsValueTuple    = _extendedType.Type.IsValueTupleType();
            _extendedType.IsValueType     = _extendedType.Type.IsValueType;
            _extendedType.IsReferenceType = _extendedType.Type.IsClass;
            _extendedType.IsStruct        = _extendedType.Type.IsValueType && !_extendedType.Type.IsEnum && !_extendedType.Type.IsPrimitive && !_extendedType.Type.IsClass;
            _extendedType.IsPrimitive     = _extendedType.Type.IsPrimitive;
            _extendedType.IsInterface     = _extendedType.Type.IsInterface;
            if (_extendedType.IsInterface && _options.BitwiseHasFlag(TypeSupportOptions.ConcreteTypes))
            {
                _extendedType.KnownConcreteTypes = GetConcreteTypes(_extendedType.Type);
            }
            _extendedType.Interfaces = _extendedType.Type.GetInterfaces();
            _extendedType.IsEnum     = _extendedType.Type.IsEnum;
            if (_extendedType.IsEnum)
            {
                _extendedType.EnumType   = _extendedType.Type.GetEnumUnderlyingType();
                _extendedType.EnumValues = _extendedType.Type.ToListOfKeyValuePairs(_extendedType.EnumType).ToList();
            }

            if (_options.BitwiseHasFlag(TypeSupportOptions.Collections))
            {
                if (typeof(IEnumerable).IsAssignableFrom(_extendedType.Type))
                {
                    _extendedType.IsEnumerable = true;
                    if (_extendedType.IsGeneric)
                    {
                        var genericArgument = _extendedType.Type.GetGenericArguments().FirstOrDefault();
                        if (genericArgument != null)
                        {
                            _extendedType.ElementType = genericArgument;
                        }
                        if (_extendedType.ElementType != null)
                        {
                            _extendedType.ElementNullableBaseType = GetNullableBaseType(_extendedType.ElementType);
                        }
                    }

                    // inspect the interfaces for a generic type
                    if (_extendedType.ElementType == null)
                    {
                        foreach (var @interface in _extendedType.Interfaces)
                        {
                            // if the class implements any generic interface, it can be considered generic
                            if (@interface.IsAssignableFrom(_extendedType.Type) && @interface.IsGenericType)
                            {
                                _extendedType.ElementType = GetElementTypeForInterfaceType(@interface);
                            }
                        }
                    }
                }
            }

            if (_extendedType.IsGeneric)
            {
                InspectGenericType(_extendedType, _extendedType.Type, _options);
            }
            else
            {
                if (_options.BitwiseHasFlag(TypeSupportOptions.Collections))
                {
                    if (!_extendedType.Type.IsArray &&
                        (typeof(ICollection).IsAssignableFrom(_extendedType.Type) ||
                         typeof(IList).IsAssignableFrom(_extendedType.Type)
                        )
                        )
                    {
                        _extendedType.IsCollection = true;
                        _extendedType.ElementType  = typeof(object);
                        _extendedType.GenericArgumentTypes.Add(typeof(object));
                    }

                    if (typeof(IDictionary).IsAssignableFrom(_extendedType.Type))
                    {
                        _extendedType.IsDictionary = true;
                        _extendedType.ElementType  = typeof(object);
                    }
                }
            }

            if (typeof(Delegate).IsAssignableFrom(_extendedType.Type))
            {
                _extendedType.IsDelegate = true;
            }

            if (_options.BitwiseHasFlag(TypeSupportOptions.Indexers))
            {
                _extendedType.HasIndexer = _extendedType.Properties.Select(x => x.PropertyInfo.GetIndexParameters())
                                           .Where(x => x.Length > 0)
                                           .Any();

                if (_extendedType.HasIndexer)
                {
                    // c# only allows a single indexer
                    var indexerProperty = _extendedType.Properties.Where(x => x.PropertyInfo.GetIndexParameters().Length > 0).ToList();
                    var indexParameters = indexerProperty.FirstOrDefault().PropertyInfo.GetIndexParameters().FirstOrDefault();
                    _extendedType.IndexerType       = indexParameters.ParameterType;
                    _extendedType.IndexerReturnType = indexerProperty.FirstOrDefault().PropertyInfo.PropertyType;
                }
            }

            // nullable
            var nullableBaseType = GetNullableBaseType(_extendedType.Type);
            _extendedType.NullableBaseType = nullableBaseType ?? _extendedType.Type;
            _extendedType.IsNullable       = nullableBaseType != null;

            // anonymous
            _extendedType.IsAnonymous = Attribute.IsDefined(_extendedType.Type, typeof(CompilerGeneratedAttribute), false) &&
                                        _extendedType.Type.IsGenericType && _extendedType.Type.Name.Contains("AnonymousType") &&
                                        (_extendedType.Type.Name.StartsWith("<>") || _extendedType.Type.Name.StartsWith("VB$")) &&
                                        (_extendedType.Type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;

            // provide a way to detect if the type requires additional concrete information in order to be serialized
            _extendedType.IsConcreteType = !(_extendedType.IsAbstract || _extendedType.IsInterface || _extendedType.IsAnonymous || _extendedType.Type == typeof(object));
        }