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.
How would you handle competing overloads of
Configure
that match the interface method signature?