Skip to content

Latest commit

 

History

History
 
 

Autofac.CodeGen

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Autofac.CodeGen

This project is an incremental roslyn source generator whose job it is to auto-generate the extension methods in RegistrationExtensions that take a delegate with a variable number of dynamically-typed arguments for injection.

For each number of arguments we accept, we must generate:

  • A Register extension method that takes a delegate containing each generic argument.

    public static IRegistrationBuilder<TComponent, SimpleActivatorData, SingleRegistrationStyle>
        Register<TDependency1, TDependency2, TComponent>(
            this ContainerBuilder builder,
            Func<TDependency1, TDependency2, TComponent> @delegate)
        where TDependency1 : notnull
        where TDependency2 : notnull
    {
      // ... snip ...
    }
  • A similar Register extension method that also takes an IComponentContext argument as the first delegate argument before any generic types.

    public static IRegistrationBuilder<TComponent, SimpleActivatorData, SingleRegistrationStyle>
        Register<TDependency1, TDependency2, TComponent>(
            this ContainerBuilder builder,
            Func<IComponentContext, TDependency1, TDependency2, TComponent> @delegate)
        where TDependency1 : notnull
        where TDependency2 : notnull
    {
      // ... snip ...
    }
  • An open generic DelegateInvoker class derived from Autofac.Core.Resolving.BaseGenericResolveDelegateInvoker that holds the delegate for each registration.

    public sealed class DelegateInvoker2<TDependency1, TDependency2, TComponent> : BaseGenericResolveDelegateInvoker
        where TDependency1 : notnull
        where TDependency2 : notnull
    {
        private readonly Func<TDependency1, TDependency2, TComponent> _delegate;
    
        public DelegateInvoker2(Func<TDependency1, TDependency2, TComponent> @delegate)
        {
            _delegate = @delegate;
        }
    
        // ... snip ...
    }
  • An open generic DelegateInvokerWithComponentContext class, same as the preceding one, but supports the IComponentContext argument to the delegate.

    public sealed class DelegateInvoker2WithComponentContext<TDependency1, TDependency2, TComponent> : BaseGenericResolveDelegateInvoker
        where TDependency1 : notnull
        where TDependency2 : notnull
    {
        private readonly Func<IComponentContext, TDependency1, TDependency2, TComponent> _delegate;
    
        public DelegateInvoker2WithComponentContext(Func<IComponentContext, TDependency1, TDependency2, TComponent> @delegate)
        {
            _delegate = @delegate;
        }
    
        // ... snip ...
    }

This project is only referenced by the Autofac project in this solution, and is not distributed as a NuGet package.

Generated Files

The files generated by this generator will end up in the obj/{config}/{tfm}/generated folder in the Autofac project, because we have <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> turned on in the Autofac csproj file.

Tests

The tests for the code generator are in the Autofac.Test.CodeGen project.

Making Changes

When making changes to the generator, the correct order of work to make sure your changes reliably show up in intellisense is:

  • Update the generator code as you need.
  • Run the tests in Autofac.Test.CodeGen; verify that the outputted code is what you expect.
  • When you're confident the output looks good, restart Visual Studio and VS Code to see your changes reflected.

Why the need to restart? Visual Studio and Omnisharp in VSCode load source generators for intellisense once, when they are first used, and does not unload them, so any subsequent changes are not picked up.

Running the build on the cli with dotnet build will correctly build the generator and use the latest generated code every time, so if you see some cases where your IDE isn't picking up the changes check the CLI build produces sensible results.