Table of Contents

Assembly service

IAssemblyService caches filtered type lookups across the currently-loaded assemblies. It exists for the case where you need the same TypeInfo[] repeatedly — GetTypes(cacheKey, …) returns the cached array on every call after the first.

Registration

using Tharga.Runtime;

builder.Services.AddAssemblyService();

AddAssemblyService registers IAssemblyService as a singleton. The cache is process-wide.

Lookup

Two forms — one that primes the cache on first call, one that requires a prior LoadTypes.

// Self-priming: filter is used the first time, ignored after.
var handlers = assemblyService.GetTypes(
    "handlers",
    x => x.IsOfType<IHandler>() && !x.IsAbstract);

// Pre-primed: filterless GetTypes requires an earlier LoadTypes
// with the same key, otherwise it throws InvalidOperationException.
assemblyService.LoadTypes("handlers", x => x.IsOfType<IHandler>() && !x.IsAbstract);

// Anywhere later:
var cached = assemblyService.GetTypes("handlers");

Calling GetTypes(key) (no filter) before the key has been populated throws — there's nothing to return.

How the assembly set is determined

By default the scan covers the entry assembly plus every assembly in AppDomain.CurrentDomain whose FullName starts with the same root namespace segment as the entry assembly (e.g. Tharga.* if the entry assembly is Tharga.Foo). This is a deliberate trade-off — restricting to one namespace family avoids scanning unrelated SDK and framework assemblies, which is faster and avoids ReflectionTypeLoadException from unrelated dependencies.

Override the scope with assemblies (explicit list) or baseAssembly (different starting point):

assemblyService.LoadTypes(
    "handlers",
    x => x.IsOfType<IHandler>(),
    baseAssembly: typeof(SomeMarker).Assembly);

Static helpers

For one-off scans where you don't want the cache, the static methods on AssemblyService are usable directly:

var allHandlers = AssemblyService.GetTypes<IHandler>(filter: x => !x.IsAbstract);
var loaded      = AssemblyService.GetLoadedAssemblies();

When to use the cache vs. the static helpers

Scenario Use
Same filter resolved repeatedly during the request/operation lifetime IAssemblyService.GetTypes(key, filter)
Single scan at startup (e.g. DI registration) AssemblyService.GetTypes(filter) or the IServiceCollection filter extensions
Lookup by a key shared across components LoadTypes once, then GetTypes(key) everywhere