IIndagoProvider
IIndagoProvider
Section titled “IIndagoProvider”IIndagoProvider is the primary entry point for all compile-time scanning operations in Indago. At build time, the Roslyn source generator emits a concrete IndagoProvider implementation of this interface into your assembly. You access it through the generated static IndagoProvider.Instance property — no manual instantiation, no reflection.
Accessing the Provider
Section titled “Accessing the Provider”IndagoProvider.Instance
Section titled “IndagoProvider.Instance”public static IIndagoProvider Instance { get; }The source generator emits a concrete IndagoProvider class into your assembly and exposes it through the static Instance property. This is the entry point for all scanning — access it directly, with no reflection or Activator.CreateInstance involved:
IIndagoProvider provider = IndagoProvider.Instance;IndagoProvider is internal to the assembly the generator runs in, so Instance is available anywhere in that same assembly. Hold the returned IIndagoProvider in a field or local, or call GetAssemblies, GetTypes, and Scan on it inline.
GetArgumentExpressionHash(string)
Section titled “GetArgumentExpressionHash(string)”[EditorBrowsable(EditorBrowsableState.Never)]static string GetArgumentExpressionHash(string argumentExpression);Converts a selector expression string into a stable, compact key. Whitespace (spaces, tabs, newlines) is stripped before hashing so that formatting changes do not invalidate the cache. The resulting hash is an MD5-based Base64 string.
This method is marked [EditorBrowsable(Never)] — it is called by generated code, not by application code.
Why it matters: The generator keys every generated scan result to the text of the selector lambda at its call site. When the lambda changes (e.g. you add .AssignableTo<INewService>()), the hash changes, and the generator produces new output. Call sites that share the same expression text share the same generated result.
Instance Methods
Section titled “Instance Methods”All three scanning methods share the same hidden caller-info parameters:
| Parameter | Attribute | Purpose |
|---|---|---|
lineNumber | [CallerLineNumber] | Line number of the call site |
filePath | [CallerFilePath] | File path of the call site |
argumentExpression | [CallerArgumentExpression] | Text of the selector argument |
The compiler fills these in automatically. Do not pass them explicitly. The generator uses all three together to locate the exact call site and associate it with the generated output.
GetAssemblies
Section titled “GetAssemblies”IEnumerable<Assembly> GetAssemblies( Action<IReflectionAssemblySelector> action, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string filePath = "", [CallerArgumentExpression(nameof(action))] string argumentExpression = "");Returns the set of Assembly objects that match the selector. The selector is expressed as an Action<IReflectionAssemblySelector>; the generator resolves the full list at build time. At runtime the generated implementation returns a pre-built collection — no reflection occurs.
Example:
IEnumerable<Assembly> assemblies = provider.GetAssemblies( s => s.FromAssemblyOf<MyApp>());GetTypes
Section titled “GetTypes”IEnumerable<Type> GetTypes( Func<IReflectionTypeSelector, IEnumerable<Type>> selector, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string filePath = "", [CallerArgumentExpression(nameof(selector))] string argumentExpression = "");Returns the set of Type objects that match the selector. The selector is a Func that receives an IReflectionTypeSelector and returns a filtered IEnumerable<Type>. The generator evaluates the selector expression at build time.
Example:
IEnumerable<Type> types = provider.GetTypes( s => s.FromAssemblyOf<MyApp>() .GetTypes(f => f.AssignableTo<IMyService>()));IServiceCollection Scan( IServiceCollection services, Action<IServiceDescriptorAssemblySelector> selector, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string filePath = "", [CallerArgumentExpression(nameof(selector))] string argumentExpression = "");Adds ServiceDescriptor entries to the supplied IServiceCollection based on the selector. Returns the same IServiceCollection so calls can be chained. The full list of registrations is resolved at build time; the generated implementation performs no reflection at runtime.
Example:
services = provider.Scan( services, s => s.FromAssemblyOf<MyApp>() .AddClasses(c => c.AssignableTo<IMyService>()) .AsImplementedInterfaces() .WithScopedLifetime());Why the selector expression text matters
Section titled “Why the selector expression text matters”Because the generator captures the text of each selector argument via [CallerArgumentExpression], the text is the identity of a call site. Two calls with identical expression text (after whitespace normalisation) share a single generated code path. A call site whose selector text changes between builds produces new generated output on the next build. This is why you should avoid dynamic string construction or code-generated selectors — the generator cannot evaluate them.
See also
Section titled “See also”- Type Filters — the fluent API used inside selectors
- ServiceRegistrationAttribute — attribute-driven registration alternative
- ExcludeFromIndagoAttribute — opt an assembly out of scanning