/// <summary>
        /// Create for repository, and return an instance of runtime repository metadata object.
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TImplement"></typeparam>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public static RepositoryReflector Create <TService, TImplement>()
            where TService : IRepository
            where TImplement : class, TService
        {
            var typeOfService   = typeof(TService);
            var typeOfImplement = typeof(TImplement);

            if (typeOfImplement.IsInterface || typeOfImplement.IsAbstract)
            {
                throw new ArgumentException($"The implement type {typeOfImplement} cannot be created an instance.");
            }

            if (typeOfService.IsInterface)
            {
                var attribute = TypeReflections.GetAttribute <RepositoryAttribute>(typeOfService);
                return(CreateCore(typeOfService, typeOfImplement, MappingType.InterfaceToClass, GetName(typeOfImplement, attribute)));
            }

            if (typeOfService.IsClass && typeOfService.IsAbstract)
            {
                var attribute = TypeReflections.GetAttribute <RepositoryAttribute>(typeOfService);
                return(CreateCore(typeOfService, typeOfImplement, MappingType.AbstractToClass, GetName(typeOfImplement, attribute)));
            }

            if (typeOfService.IsClass)
            {
                var attribute = TypeReflections.GetAttribute <RepositoryAttribute>(typeOfService);
                return(CreateCore(typeOfService, typeOfImplement, MappingType.ClassToClass, GetName(typeOfImplement, attribute)));
            }

            throw new InvalidOperationException("Unknown service type.");
        }
        public void GenericTypeGettingAttributeTest()
        {
            var type = typeof(NormalWithAttrClass);

            TypeReflections.GetAttribute <ModelOneAttribute>(type).ShouldNotBeNull();
            TypeReflections.GetAttribute <ModelTwoAttribute>(type).ShouldBeNull();
            TypeReflections.GetAttribute <ModelThreeAttribute>(type).ShouldNotBeNull();
        }
        public void DirectTypeGettingAttributeTest()
        {
            var type  = typeof(NormalWithAttrClass);
            var one   = typeof(ModelOneAttribute);
            var two   = typeof(ModelTwoAttribute);
            var three = typeof(ModelThreeAttribute);

            TypeReflections.GetAttribute(type, one).ShouldNotBeNull();
            TypeReflections.GetAttribute(type, two).ShouldBeNull();
            TypeReflections.GetAttribute(type, three).ShouldNotBeNull();
        }
        public void GenericTypeGettingAttributeInheritTest()
        {
            var type = typeof(NormalWithAttrClassWrapper2);

            TypeReflections.GetAttribute <ModelOneAttribute>(type).ShouldBeNull();
            TypeReflections.GetAttribute <ModelTwoAttribute>(type).ShouldBeNull();
            TypeReflections.GetAttribute <ModelThreeAttribute>(type).ShouldBeNull();
            TypeReflections.GetAttribute <ModelFourAttribute>(type).ShouldNotBeNull();

            Assert.Throws <AmbiguousMatchException>(() => TypeReflections.GetAttribute <ModelOneAttribute>(type, ReflectionOptions.Inherit));
            TypeReflections.GetAttribute <ModelOneAttribute>(type, ReflectionOptions.Inherit, ReflectionAmbiguousOptions.IgnoreAmbiguous).ShouldNotBeNull();
            TypeReflections.GetAttribute <ModelTwoAttribute>(type, ReflectionOptions.Inherit).ShouldBeNull();
            TypeReflections.GetAttribute <ModelThreeAttribute>(type, ReflectionOptions.Inherit).ShouldNotBeNull();
            TypeReflections.GetAttribute <ModelFourAttribute>(type, ReflectionOptions.Inherit).ShouldNotBeNull();
        }
        public void DirectTypeGettingAttributeInheritTest()
        {
            var type  = typeof(NormalWithAttrClassWrapper2);
            var one   = typeof(ModelOneAttribute);
            var two   = typeof(ModelTwoAttribute);
            var three = typeof(ModelThreeAttribute);
            var four  = typeof(ModelFourAttribute);

            TypeReflections.GetAttribute(type, one).ShouldBeNull();
            TypeReflections.GetAttribute(type, two).ShouldBeNull();
            TypeReflections.GetAttribute(type, three).ShouldBeNull();
            TypeReflections.GetAttribute(type, four).ShouldNotBeNull();

            Assert.Throws <AmbiguousMatchException>(() => TypeReflections.GetAttribute(type, one, ReflectionOptions.Inherit));
            TypeReflections.GetAttribute(type, one, ReflectionOptions.Inherit, ReflectionAmbiguousOptions.IgnoreAmbiguous).ShouldNotBeNull();
            TypeReflections.GetAttribute(type, two, ReflectionOptions.Inherit).ShouldBeNull();
            TypeReflections.GetAttribute(type, three, ReflectionOptions.Inherit).ShouldNotBeNull();
            TypeReflections.GetAttribute(type, four, ReflectionOptions.Inherit).ShouldNotBeNull();
        }
        /// <summary>
        /// Create for repository, and return an instance of runtime repository metadata object.
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public static RepositoryReflector Create <TService>()
        {
            var typeOfService = typeof(TService);

            if (typeOfService.IsInterface)
            {
                var attribute = TypeReflections.GetAttribute <RepositoryAttribute>(typeOfService);

                if (attribute is null)
                {
                    throw new InvalidOperationException("Cannot find the target type for this interface.");
                }

                var typeOfImplement = attribute.MapTo;

                if (typeOfImplement is null)
                {
                    throw new InvalidOperationException("The target type for this interface cannot be null.");
                }

                if (typeOfImplement.IsInterface || typeOfImplement.IsAbstract)
                {
                    throw new ArgumentException($"The implement type {typeOfImplement} cannot be created an instance.");
                }

                return(CreateCore(typeOfService, typeOfImplement, MappingType.InterfaceToClass, GetName(typeOfImplement, attribute)));
            }

            if (typeOfService.IsAbstract)
            {
                throw new ArgumentException($"The abstract service type {typeOfService} cannot be created an instance.");
            }

            if (typeOfService.IsClass)
            {
                var attribute = TypeReflections.GetAttribute <RepositoryAttribute>(typeOfService);
                return(CreateCore(typeOfService, typeOfService, MappingType.ClassSelf, GetName(typeOfService, attribute)));
            }

            throw new InvalidOperationException("Unknown service type.");
        }