Skip to content

Instantly share code, notes, and snippets.

@davidfowl
Last active December 14, 2015 01:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidfowl/700097cca459c1e78c86 to your computer and use it in GitHub Desktop.
Save davidfowl/700097cca459c1e78c86 to your computer and use it in GitHub Desktop.
Typesafe params

In the new ASP.NET 5 stack dependency injection is pervasive. We let users wire up their dependencies in the Startup class:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<IFoo, Foo>();
    }
    
    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IFoo foo)
    {
        loggerFactory.AddConsole();
        
        app.UseMvc();
    }
}

In the above snippet, the Configure method has a single required parameter, all other parameters are optional. Let's say we wanted to define an interface for this class so that we get type safety and the benefits of refactoring:

public interface IStartup
{
    void ConfigureServices(IServiceCollection services);
    void Configure(IApplicationBuilder app, object params[] args);
}

The problem with this is that the implemenation of the interface can't get ILoggerFactory and IFoo without casting from object.

Enter type safe params:

public interface IStartup
{
    void ConfigureServices(IServiceCollection services);
    void Configure(IApplicationBuilder app, any params[] args);
}
public class Startup : IStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }
    
    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IFoo environment)
    {
        loggerFactory.AddConsole();
        
        app.UseMvc();
    }
}

The compiler would generate:

public class Startup : IStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    [CompilerGenerated]
    void IStartup.Configure(IApplicationBuilder app, params object[] args)
    {
        Configure(app, (ILoggerFactory)args[0], (IFoo)args[1]);
    }

    // User defined method
    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IFoo environment)
    {
        loggerFactory.AddConsole();

        app.UseMvc();
    }
}

This only helps the user implementing the interface, the caller is likely still using reflection to call the user method.

@mdekrey
Copy link

mdekrey commented Jul 6, 2015

👍 I highly approve, especially given the SO question @davidfowl linked. Reminds me of TypeScript's ...params: any[] usage in an interface, which is used with JavaScript DI frameworks, such as AngularJS's.

Would it work for delegate types? I would be adding this to my DI usage so fast...

delegate void InjectableAction(any params[] args);

interface IDependencyInjector 
{
    void Invoke(InjectableAction target);
}

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