0

I have the following use case:

I have created generic-endpoint strucure in my ASP.NET Core WebAPi project.

And now I want to write an extention method to ServiceCollection to register my Endpoints to DI easily.

Now I will try to demonstrate what I want. Let's say we have:

interface IEndPoint<TInput, TOutput>
{
    TOutput Execute(TInput input);
}

class StrToIntEndPoint : IEndPoint<string, int>
{
    public int Execute(string input)
    {
        return int.Parse(input);
    }
}

class ServiceCollection { }

static class ServiceCollectionServiceExtensions
{
    public static void AddScoped<TService, TImplementation>(this ServiceCollection services) where TImplementation : TService
    {

    }
}

static class MyCustomExt
{
    // Here, I have to add TInput, TOutput type parameters to AddEndpoint method too.
    public static void AddEndpoint<T, TInput, TOutput>(this ServiceCollection services) where T: IEndPoint<TInput, TOutput>
    {
        services.AddScoped<IEndPoint<TInput, TOutput>, T>();
    }
}

class Program
{
    static void Main()
    {
        var services = new ServiceCollection();

        // Compile Error: Incorrect number of type parameters
        services.AddEndpoint<StrToIntEndPoint>();

        // fine
        services.AddEndpoint<StrToIntEndPoint, string, int>();

    }
}

My question is why compiler doesn't resolve string and int as type parameters for AddEndpoint via refering to StrToIntEndPoint?

Sanan Fataliyev
  • 612
  • 8
  • 16
  • 1
    This is called *partial Inference*, and *.Net* doesn't support it, its an *all-or-nothing* affair. However, depending on how far you want to go down this *rabbit-hole* and how much *type safety* you want to loose, there are *hacks* you can do, however non of them are satisfying – TheGeneral May 24 '19 at 23:12
  • Arg. loose = lose – TheGeneral May 24 '19 at 23:21
  • @TheGeneral thanks for the term, i didn't know, that's why I wrote code) – Sanan Fataliyev May 24 '19 at 23:22

2 Answers2

1

Sadly it’s just not the way generic constraints/arguments work. You either specify NO generic type arguments and the compiler infers all arguments, or you specify all of them.

Jeff
  • 35,755
  • 15
  • 108
  • 220
1

I ended up with the following solution for my case:

static class MyCustomExt
{
    public static IServiceCollection AddScopedWitInterfaces<T>(this IServiceCollection services)
    {
        Type type = typeof(T);

        Type[] interfaces = type.GetInterfaces();

        foreach (Type interfaceType in interfaces)
        {
            services.AddScoped(interfaceType, type);
        }

        return services;
    }
}

And register my service in ConfigureServices:

services.AddScopedWitInterfaces<StrToIntEndpoint>();
Sanan Fataliyev
  • 612
  • 8
  • 16