Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AutoRegister registers over 10k types when using in Xamarin.Forms #139

Open
BenBtg opened this issue Jun 19, 2020 · 4 comments
Open

AutoRegister registers over 10k types when using in Xamarin.Forms #139

BenBtg opened this issue Jun 19, 2020 · 4 comments

Comments

@BenBtg
Copy link

BenBtg commented Jun 19, 2020

AutoRegister takes ages (over 10 seconds to complete as it seems to register over 10,000 types.
For example see AutoRegister

@niemyjski
Copy link
Collaborator

Have you done any profiling to see why it's taking so much time?

@grumpydev
Copy link
Owner

You could also pass a predicate to AutoRegister to exclude anything in that assembly, and/or update IsIgnoredAssembly to ignore it (would be nice to add a public collection property that would let you add to that ignored assembly list).

@niemyjski
Copy link
Collaborator

Does it seem like a bad practice to do auto registrations in general?

@Law85
Copy link

Law85 commented Nov 14, 2020

Just wanted to add something to this. I was hacking the current TinyIOC.cs file with an older version of the file as reference that was working and found that by replacing registration region with the below snippet and updating the AutoRegisterInternal function with the older version of the function it no longer autoregisters the all the xf assemblys and seems to work.

I haven't had a chance to investigate why yet the main difference seems to be how it handles the ignoreDuplicateImplementations within the registration.

This is probably a classic case of me fuxing something (fixing one thing and breaking 20 other things in the process) but It might help you guys pin point the issue with XF.

Updated Code

#region Registration
///


/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
///
/// If more than one class implements an interface then only one implementation will be registered
/// although no error will be thrown.
///

public void AutoRegister()
{
AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, true, null);
}

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
    /// Types will only be registered if they pass the supplied registration predicate.
    /// 
    /// If more than one class implements an interface then only one implementation will be registered
    /// although no error will be thrown.
    /// </summary>
    /// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
    public void AutoRegister(Func<Type, bool> registrationPredicate)
    {
        AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, true, registrationPredicate);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
    /// </summary>
    /// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
    /// <exception cref="TinyIoCAutoRegistrationException"/>
    public void AutoRegister(bool ignoreDuplicateImplementations)
    {
        AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, null);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
    /// Types will only be registered if they pass the supplied registration predicate.
    /// </summary>
    /// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
    /// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
    /// <exception cref="TinyIoCAutoRegistrationException"/>
    public void AutoRegister(bool ignoreDuplicateImplementations, Func<Type, bool> registrationPredicate)
    {
        AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, registrationPredicate);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
    /// 
    /// If more than one class implements an interface then only one implementation will be registered
    /// although no error will be thrown.
    /// </summary>
    /// <param name="assemblies">Assemblies to process</param>
    public void AutoRegister(IEnumerable<Assembly> assemblies)
    {
        AutoRegisterInternal(assemblies, true, null);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
    /// Types will only be registered if they pass the supplied registration predicate.
    /// 
    /// If more than one class implements an interface then only one implementation will be registered
    /// although no error will be thrown.
    /// </summary>
    /// <param name="assemblies">Assemblies to process</param>
    /// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
    public void AutoRegister(IEnumerable<Assembly> assemblies, Func<Type, bool> registrationPredicate)
    {
        AutoRegisterInternal(assemblies, true, registrationPredicate);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
    /// </summary>
    /// <param name="assemblies">Assemblies to process</param>
    /// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
    /// <exception cref="TinyIoCAutoRegistrationException"/>
    public void AutoRegister(IEnumerable<Assembly> assemblies, bool ignoreDuplicateImplementations)
    {
        AutoRegisterInternal(assemblies, ignoreDuplicateImplementations, null);
    }

    /// <summary>
    /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
    /// Types will only be registered if they pass the supplied registration predicate.
    /// </summary>
    /// <param name="assemblies">Assemblies to process</param>
    /// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
    /// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
    /// <exception cref="TinyIoCAutoRegistrationException"/>
    public void AutoRegister(IEnumerable<Assembly> assemblies, bool ignoreDuplicateImplementations, Func<Type, bool> registrationPredicate)
    {
        AutoRegisterInternal(assemblies, ignoreDuplicateImplementations, registrationPredicate);
    }

    /// <summary>
    /// Creates/replaces a container class registration with default options.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType)
    {
        return RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerType));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with default options.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, string name)
    {
        return RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerType));

    }

    /// <summary>
    /// Creates/replaces a container class registration with a given implementation and default options.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Type registerImplementation)
    {
        return this.RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerImplementation));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a given implementation and default options.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Type registerImplementation, string name)
    {
        return this.RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerImplementation));
    }

    /// <summary>
    /// Creates/replaces a container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="instance">Instance of RegisterType to register</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, object instance)
    {
        return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerType, instance));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="instance">Instance of RegisterType to register</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, object instance, string name)
    {
        return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerType, instance));
    }

    /// <summary>
    /// Creates/replaces a container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
    /// <param name="instance">Instance of RegisterImplementation to register</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Type registerImplementation, object instance)
    {
        return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerImplementation, instance));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
    /// <param name="instance">Instance of RegisterImplementation to register</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Type registerImplementation, object instance, string name)
    {
        return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerImplementation, instance));
    }

    /// <summary>
    /// Creates/replaces a container class registration with a user specified factory
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory)
    {
        return RegisterInternal(registerType, string.Empty, new DelegateFactory(registerType, factory));
    }

    /// <summary>
    /// Creates/replaces a container class registration with a user specified factory
    /// </summary>
    /// <param name="registerType">Type to register</param>
    /// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
    /// <param name="name">Name of registation</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory, string name)
    {
        return RegisterInternal(registerType, name, new DelegateFactory(registerType, factory));
    }

    /// <summary>
    /// Creates/replaces a container class registration with default options.
    /// </summary>
    /// <typeparam name="RegisterImplementation">Type to register</typeparam>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>()
        where RegisterType : class
    {
        return this.Register(typeof(RegisterType));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with default options.
    /// </summary>
    /// <typeparam name="RegisterImplementation">Type to register</typeparam>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>(string name)
        where RegisterType : class
    {
        return this.Register(typeof(RegisterType), name);
    }

    /// <summary>
    /// Creates/replaces a container class registration with a given implementation and default options.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType, RegisterImplementation>()
        where RegisterType : class
        where RegisterImplementation : class, RegisterType
    {
        return this.Register(typeof(RegisterType), typeof(RegisterImplementation));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a given implementation and default options.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType, RegisterImplementation>(string name)
        where RegisterType : class
        where RegisterImplementation : class, RegisterType
    {
        return this.Register(typeof(RegisterType), typeof(RegisterImplementation), name);
    }

    /// <summary>
    /// Creates/replaces a container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <param name="instance">Instance of RegisterType to register</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>(RegisterType instance)
        where RegisterType : class
    {
        return this.Register(typeof(RegisterType), instance);
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <param name="instance">Instance of RegisterType to register</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>(RegisterType instance, string name)
        where RegisterType : class
    {
        return this.Register(typeof(RegisterType), instance, name);
    }

    /// <summary>
    /// Creates/replaces a container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
    /// <param name="instance">Instance of RegisterImplementation to register</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance)
        where RegisterType : class
        where RegisterImplementation : class, RegisterType
    {
        return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance);
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a specific, strong referenced, instance.
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
    /// <param name="instance">Instance of RegisterImplementation to register</param>
    /// <param name="name">Name of registration</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance, string name)
        where RegisterType : class
        where RegisterImplementation : class, RegisterType
    {
        return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance, name);
    }

    /// <summary>
    /// Creates/replaces a container class registration with a user specified factory
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory)
        where RegisterType : class
    {
        if (factory == null)
        {
            throw new ArgumentNullException("factory");
        }

        return this.Register(typeof(RegisterType), (c, o) => factory(c, o));
    }

    /// <summary>
    /// Creates/replaces a named container class registration with a user specified factory
    /// </summary>
    /// <typeparam name="RegisterType">Type to register</typeparam>
    /// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
    /// <param name="name">Name of registation</param>
    /// <returns>RegisterOptions for fluent API</returns>
    public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory, string name)
        where RegisterType : class
    {
        if (factory == null)
        {
            throw new ArgumentNullException("factory");
        }

        return this.Register(typeof(RegisterType), (c, o) => factory(c, o), name);
    }

    /// <summary>
    /// Register multiple implementations of a type.
    /// 
    /// Internally this registers each implementation using the full name of the class as its registration name.
    /// </summary>
    /// <typeparam name="RegisterType">Type that each implementation implements</typeparam>
    /// <param name="implementationTypes">Types that implement RegisterType</param>
    /// <returns>MultiRegisterOptions for the fluent API</returns>
    public MultiRegisterOptions RegisterMultiple<RegisterType>(IEnumerable<Type> implementationTypes)
    {
        return RegisterMultiple(typeof(RegisterType), implementationTypes);
    }

    /// <summary>
    /// Register multiple implementations of a type.
    /// 
    /// Internally this registers each implementation using the full name of the class as its registration name.
    /// </summary>
    /// <param name="registrationType">Type that each implementation implements</param>
    /// <param name="implementationTypes">Types that implement RegisterType</param>
    /// <returns>MultiRegisterOptions for the fluent API</returns>
    public MultiRegisterOptions RegisterMultiple(Type registrationType, IEnumerable<Type> implementationTypes)
    {
        if (implementationTypes == null)
            throw new ArgumentNullException("types", "types is null.");

        foreach (var type in implementationTypes)
            if (!registrationType.IsAssignableFrom(type))
                throw new ArgumentException(String.Format("types: The type {0} is not assignable from {1}", registrationType.FullName, type.FullName));

        if (implementationTypes.Count() != implementationTypes.Distinct().Count())
        {
            var queryForDuplicatedTypes = from i in implementationTypes
                                          group i by i
                into j
                                          where j.Count() > 1
                                          select j.Key.FullName;

            var fullNamesOfDuplicatedTypes = string.Join(",\n", queryForDuplicatedTypes.ToArray());
            var multipleRegMessage = string.Format("types: The same implementation type cannot be specified multiple times for {0}\n\n{1}", registrationType.FullName, fullNamesOfDuplicatedTypes);
            throw new ArgumentException(multipleRegMessage);
        }

        var registerOptions = new List<RegisterOptions>();

        foreach (var type in implementationTypes)
        {
            registerOptions.Add(Register(registrationType, type, type.FullName));
        }

        return new MultiRegisterOptions(registerOptions);
    }
    #endregion

private void AutoRegisterInternal(IEnumerable assemblies, bool ignoreDuplicateImplementations, Func<Type, bool> registrationPredicate)
{
lock (_AutoRegisterLock)
{
var types = assemblies.SelectMany(a => a.SafeGetTypes()).Where(t => !IsIgnoredType(t, registrationPredicate)).ToList();

            var concreteTypes = from type in types
                                where (type.IsClass() == true) && (type.IsAbstract() == false) && (type != this.GetType() && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition()))
                                select type;

            foreach (var type in concreteTypes)
            {
                try
                {
                    RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, type));
                }
                catch (MethodAccessException)
                {
                    // Ignore methods we can't access - added for Silverlight
                }
            }

            var abstractInterfaceTypes = from type in types
                                         where ((type.IsInterface() == true || type.IsAbstract() == true) && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition()))
                                         select type;

            foreach (var type in abstractInterfaceTypes)
            {
                var implementations = from implementationType in concreteTypes
                                      where implementationType.GetInterfaces().Contains(type) || implementationType.BaseType() == type
                                      select implementationType;

                if (!ignoreDuplicateImplementations && implementations.Count() > 1)
                    throw new TinyIoCAutoRegistrationException(type, implementations);

                var firstImplementation = implementations.FirstOrDefault();
                if (firstImplementation != null)
                {
                    try
                    {
                        RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, firstImplementation));
                    }
                    catch (MethodAccessException)
                    {
                        // Ignore methods we can't access - added for Silverlight
                    }
                }
            }
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants