Skip to content

Instantly share code, notes, and snippets.

@Grinderofl
Created November 1, 2018 09:12
Show Gist options
  • Save Grinderofl/9e3e0b2defadb912b2f463a5c8cb118c to your computer and use it in GitHub Desktop.
Save Grinderofl/9e3e0b2defadb912b2f463a5c8cb118c to your computer and use it in GitHub Desktop.
Interface implementation generator
public class ImplementationGenerator
{
private const string AddServiceFormat = "services.AddScoped<{0},{1}>();";
public string GenerateInterfaceImplementationRegistrations(IEnumerable<Assembly> assemblies)
{
var types = assemblies.SelectMany(x => x.GetExportedTypes())
.Where(x => x.GetInterfaces().Any())
.Where(x => !x.IsAbstract && !x.IsInterface)
.Where(x => x.Namespace.EndsWith(".Impl"));
var namespaces = new List<string>
{
typeof(IServiceCollection).Namespace,
typeof(ServiceCollectionServiceExtensions).Namespace
};
// namespace TicketTool.Application.Configuration
var namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(typeof(ServiceImplementations).Namespace));
var publicToken = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
var staticToken = SyntaxFactory.Token(SyntaxKind.StaticKeyword);
// IServiceCollection
var serviceCollectionTypeName = SyntaxFactory.ParseTypeName(typeof(IServiceCollection).Name);
// Configure
var configureMethodName = nameof(ServiceImplementations.Configure);
// Configure(IServiceCollection services)
var configureMethod = typeof(ServiceImplementations).GetMethod(configureMethodName);
// void
var configureMethodReturnTypeName = SyntaxFactory.ParseTypeName(configureMethod.ReturnType.Name.ToLower());
// nameof(services)
var servicesParameterName = configureMethod.GetParameters().Select(x => x.Name).First();
var servicesParameterIdentifier = SyntaxFactory.Identifier(servicesParameterName);
// public static class ServiceImplementations
var classDeclaration = SyntaxFactory.ClassDeclaration(nameof(ServiceImplementations))
.AddModifiers(publicToken, staticToken);
var body = new List<StatementSyntax>();
var typesGrouped = types.GroupBy(x => x.Namespace);
foreach (var group in typesGrouped)
{
namespaces.Add(group.Key);
foreach (var type in group)
{
var implements = type.GetInterfaces().Where(x => !x.IsGenericType);
foreach (var @interface in implements)
{
namespaces.Add(@interface.Namespace);
body.Add(SyntaxFactory.ParseStatement(string.Format(AddServiceFormat, @interface.Name, type.Name)));
}
}
}
foreach (var @namespace in namespaces.Distinct())
namespaceDeclaration = namespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(@namespace)));
var block = SyntaxFactory.Block(body);
// IServiceCollection services
var servicesParameter = SyntaxFactory.Parameter(servicesParameterIdentifier)
.WithType(serviceCollectionTypeName);
// public static void Configure(IServiceCollection services)
var configureDecl = SyntaxFactory.MethodDeclaration(configureMethodReturnTypeName, configureMethodName)
.AddModifiers(publicToken, staticToken);
configureDecl = configureDecl.AddParameterListParameters(servicesParameter)
.WithBody(block);
classDeclaration = classDeclaration.AddMembers(configureDecl);
namespaceDeclaration = namespaceDeclaration.AddMembers(classDeclaration);
return namespaceDeclaration.NormalizeWhitespace().ToFullString();
}
}
public void GenerateRegistrations()
{
var path = GetOutputFilePath("ServiceImplementations");
var assemblies = new[]
{
typeof(Startup).Assembly,
typeof(UserRepository).Assembly,
typeof(UserService).Assembly
};
var generator = new ImplementationGenerator();
var code = generator.GenerateInterfaceImplementationRegistrations(assemblies);
File.WriteAllText(path, code);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment