Skip to content

All app assemblies are loaded on startup #1443

@kzu

Description

@kzu

Steps to Reproduce

Given code like the following:

// Some static dictionary somewhere:
public static Dictionary<string, Func<object>> Services { get; } = new Dictionary<string, Func<object>>();

// From MainActivity.cs;
Services.Add(nameof(BarServices.Bar), CreateBar);
Services.Add(nameof(FooServices.Foo), CreateFoo);

And given that the two methods are defined to explicitly not be inlined or otherwise loaded until invoked:

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static object CreateBar() => new BarServices.Bar();

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static object CreateFoo() => new FooServices.Foo();

And given FooServices.dll and BarServices.dll are two completely independent assemblies from the main app's, it would be highly desirable for the assemblies to only be loaded when the dictionary entry is accessed and the delegate is invoked, instead of happening on app start, which slows down the process "unnecessarily".

The ~same code in a .NET app properly lazy loads the assemblies as needed:

        public static Dictionary<string, Func<object>> Services { get; } = new Dictionary<string, Func<object>>(StringComparer.OrdinalIgnoreCase);

        static void Main(string[] args)
        {
            // Both this approach as well as the inline lambda properly delay-load the assemblies
            //Services.Add(nameof(BarServices.Bar), CreateBar);
            //Services.Add(nameof(FooServices.Foo), CreateFoo);

            Services.Add(nameof(BarServices.Bar), () => new BarServices.Bar());
            Services.Add(nameof(FooServices.Foo), () => new FooServices.Foo());

            var line = "";
            while ((line = Console.ReadLine()).Length > 0)
            {
                Console.WriteLine(Services[line.Trim()].Invoke().ToString());
            }
        }

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        static object CreateBar() => new BarServices.Bar();

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        static object CreateFoo() => new FooServices.Foo();

This is important for apps that use assembly-partitioning to split logic across modules, which should only be loaded whenever needed (i.e. when the UI that consumes them is navigated to, say).

Expected Behavior

Assemblies are lazy-loaded.

Actual Behavior

Both assemblies are loaded up-front:

03-19 15:36:33.243    nexus_5x    Debug    13769    Mono    Assembly FooServices[0x9de4ed60] added to domain RootDomain, ref_count=1

Version Information

Currently verified against 15.7 pre2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions