// Returns type if it's a [Service] class,
        // otherwise searches for a [Service] implementing the specified interface
        private Type ClassOrVersionFromInterface(Type type, ServedAttribute servedAttribute = null)
        {
            if (type.IsInterface)
            {
                IEnumerable <Type> versions = this.instances.TypesAssignableFrom(type);

                // is there already an implementation for the interface?
                if (versions.Any())
                {
                    return(versions.First());
                }
                else
                {
                    versions = this.Version(type, servedAttribute);
                    if (versions.Any())
                    {
                        var t = versions.First();
                        MaskPass(t);
                        return(t);
                    }

                    if (servedAttribute is null)
                    {
                        throw new ImplementationNotFoundException(type, $"can't find [Service] for interface {type.Name}");
                    }
                    else
                    {
                        throw new ImplementationNotFoundException(type, $"can't find [Service] for {type.Name} v{servedAttribute.TargetVersion}");
                    }
                }
            }
            else
            {
                MaskPass(type);
                return(type);
            }


            void MaskPass(Type type)
            {
                if (this.settings.Mask.IsMasked(type))
                {
                    throw new InvalidOperationException($"Type {type.Name} is { (this.settings.Mask._isWhiteList ? "not whitelisted" : "blacklisted")}");
                }
                //todo create custom exception
            }
        }
        // returns the instantiated object
        private object InstTypeOrServiceEnum(Type type, ServedAttribute servedAttribute, ref List <object> used)
        {
            if (
                this.settings.Injection._serveEnumerables
                &&
                type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable <>)
                )
            {
                var generic = type.GetGenericArguments()[0];

                // list of sorted valid types
                var validTypes = this.Version(generic, servedAttribute).ToArray();

                // creates generic list using reflection
                var listType = typeof(List <>).MakeGenericType(generic);
                // cast to allow calling .Add()
                var instances = (IList)Activator.CreateInstance(listType);

                // gather instances if necessary
                foreach (var serviceType in validTypes)
                {
                    var obj = this.OfTypeOrInstantiate(serviceType);
                    instances.Add(obj);
                    used.Add(obj);
                }
                return(instances);
            }
            else
            {
                var serviceType = this.ClassOrVersionFromInterface(type, servedAttribute);

                var obj = this.OfTypeOrInstantiate(serviceType);
                used.Add(obj);
                return(obj);
            }
        }
        // performs versioning on the specified type
        private IEnumerable <Type> Version(Type targetType, ServedAttribute servedAttribute)
        {
            var targetVersion = servedAttribute?.TargetVersion ?? 0.0;
            var method        =
                (this.settings.Injection._overrideTargetingMethod || servedAttribute is null || !(servedAttribute._targetingDefined))
                                        ? this.settings.Injection._targetingMethod
                                        : servedAttribute.TargetingMethod;


            ////var candidateTypes = this.instances.TypesAssignableFrom(targetType);
            var candidateTypes = targetType
                                 .Assembly
                                 .GetTypes()
                                 .Where(t => t.IsClass && !t.IsAbstract && targetType.IsAssignableFrom(t));


            return(method switch
            {
                ServedVersionTargetingMethod.None
                =>
                candidateTypes,


                ServedVersionTargetingMethod.Exact
                =>
                candidateTypes
                .Where
                (
                    t =>
                    t.GetCustomAttribute <ServiceAttribute>()
                    .Version == targetVersion
                ),


                ServedVersionTargetingMethod.LatestMajor
                =>
                candidateTypes
                .Where
                (
                    t =>
                    t.GetCustomAttribute <ServiceAttribute>()
                    .Version >= targetVersion
                )
                .OrderByDescending(t => t.GetCustomAttribute <ServiceAttribute>().Version),


                ServedVersionTargetingMethod.LatestMinor
                =>
                candidateTypes
                .Where
                (
                    t =>
                {
                    var v = t.GetCustomAttribute <ServiceAttribute>().Version;
                    return
                    v >= targetVersion
                    &&
                    v < Math.Floor(targetVersion + 1);
                }
                )
                .OrderByDescending(t => t.GetCustomAttribute <ServiceAttribute>().Version),


                _ => throw new NotImplementedException()
            });