1

Using C# 10 I have the interface:

public Interface IEndpoint {
   void Map();
} 

I need to find classes that implement IEndpoint in Assembly of Program class.

Then, for each class, I need to call the method Map:

IEnumerable<IEndpoint> endpoints = 
  typeof(Program).Assembly
    .GetTypes()
    .Where(x => x.GetInterface(nameof(IEndpoint)) == typeof(IEndpoint)); 

I am getting the error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Type>' to 'System.Collections.Generic.IEnumerable<IEndpoint>'

How can I solve this and call the method Map for each found class?

Update

I think I got it:

IEnumerable<Type> types = typeof(Program).Assembly.GetTypes().Where(x => x.IsAssignableFrom(typeof(IEndpoint)) && !x.IsInterface);

foreach (Type type in types) {
  
  IEndpoint? endpoint = (IEndpoint?)Activator.CreateInstance(type);

  endpoint?.Map();

}

Am I missing something in my implementation?

I am asking because I've seen many approaches to this problem.

Not sure if mine is the most recent approach.

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • 2
    The `Map()` method is only available on instances. So when you find a matching type, you need to create an instance of it. You might look at the `Activator` class to create instances from `Type`s – Jeroen van Langen Dec 06 '21 at 14:13
  • 1
    Have you checked [this thread](https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface)? – Peter Csala Dec 06 '21 at 14:19
  • @JeroenvanLangen I've added an update ... Does it make sense to you? It complies. – Miguel Moura Dec 06 '21 at 14:22
  • @PeterCsala Yes, I have seen a few threads and I find many different approaches. So I am trying to figure which one is the most recente using C# 10. I just added an update to my thread with code that compiles. What do you think? – Miguel Moura Dec 06 '21 at 14:23
  • 1
    If you want to answer your own question, post an answer rather than an edit to the question (someone else might post an answer that you like more). If you're looking for codereview, there is a dedicated site at codereview.stackexchange.com – Caius Jard Dec 06 '21 at 14:24
  • 3
    Your implementation will work only if all implementations of IEndpoint interface has parameterless constructor. Otherwise I suggest using DI to be able to create any instance (answer below) – Szymon Tomczyk Dec 06 '21 at 14:33
  • 3
    I would change your call to `typeof(Program).Assembly.GetTypes().Where(x => typeof(IEndpoint).IsAssignableFrom(x) && !x.IsInterface)`, you're not checking the assignablefrom correctly. You need to make sure the interface is assigned to a class... – Trevor Dec 06 '21 at 14:45
  • "_Then, for each class, I need to call the method Map_" You can't call a method on a class, but calling a method on an empty instance usually makes no sense. What do you really want to do? If you want to call the method on all created objects, you have to register them first. – shingo Dec 06 '21 at 15:09

1 Answers1

2

It can be achieved using dependency injection container and scrutor nuget package. First you need to scan your assembly for IEndpoint interface and register them. Later on, using service provider, create instances of IEndpoint and run Map() method

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.Scan(s => s.FromAssemblyOf<Program>()
    .AddClasses(c => c.AssignableTo(typeof(IEndpoint)))
    .AsImplementedInterfaces()
    .WithScopedLifetime());

var serviceProvider = services.BuildServiceProvider();
using var scope = serviceProvider.CreateScope();
var endpoints = scope.ServiceProvider.GetServices<IEndpoint>().ToList();
endpoints.ForEach(e => e.Map());

public interface IEndpoint
{
    void Map();
}

public class Endpoint : IEndpoint
{
    public void Map()
    {
        Console.WriteLine("Hello world from Endpoint class");
    }
}
Szymon Tomczyk
  • 1,219
  • 11
  • 16
  • There are many errors in your example, it doesn't compile; maybe copy-pasta issue? – Trevor Dec 06 '21 at 15:45
  • I've updated to full working example on .NET 6.0, please bear in mind that Scrutor nuget package has to be referenced for Scan extension. – Szymon Tomczyk Dec 06 '21 at 16:11