我可以帮C#编译器推断出这种类型吗?

Ste*_*nds 6 c# type-inference

我遇到了类型推断和C#编译器的问题.阅读了这个问题这个问题后,我想我明白为什么它不起作用:我想知道的是,如果有任何方法可以解决问题以获得我喜欢的调用语义.

这里有一些代码说明了我的问题(对不起长度,这是我可以减少它的最短时间):

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace StackOverflow
{
    interface IQuery<TResult> { }

    class MeaningOfLifeQuery : IQuery<int> { }

    interface IQueryHandler<TQuery, TResult> where TQuery : class, IQuery<TResult>
    {
        Task<TResult> ExecuteAsync(TQuery query);
    }

    class MeaningOfLifeQueryHandler : IQueryHandler<MeaningOfLifeQuery, int>
    {
        public Task<int> ExecuteAsync(MeaningOfLifeQuery query)
        {
            return Task.FromResult(42);
        }
    }

    interface IRepository
    {
        Task<TResult> ExecuteQueryDynamicallyAsync<TResult>(IQuery<TResult> query);
        Task<TResult> ExecuteQueryStaticallyAsync<TQuery, TResult>(TQuery query)
            where TQuery : class, IQuery<TResult>;
    }

    class Repository : IRepository
    {
        public Repository(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        readonly IServiceProvider _serviceProvider;

        public async Task<TResult> ExecuteQueryDynamicallyAsync<TResult>(IQuery<TResult> query)
        {
            Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
            dynamic handler = _serviceProvider.GetRequiredService(handlerType);
            return await handler.ExecuteAsync((dynamic) query);
        }

        public async Task<TResult> ExecuteQueryStaticallyAsync<TQuery, TResult>(TQuery query)
            where TQuery : class, IQuery<TResult>
        {
            Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(typeof(TQuery), typeof(TResult));
            var handler = (IQueryHandler<TQuery, TResult>) _serviceProvider.GetRequiredService(handlerType);
            return await handler.ExecuteAsync(query);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var services = new ServiceCollection();
            services.AddTransient<IQueryHandler<MeaningOfLifeQuery, int>, MeaningOfLifeQueryHandler>();
            IServiceProvider serviceProvider = services.BuildServiceProvider();

            var repository = new Repository(serviceProvider);
            var query = new MeaningOfLifeQuery();
            int result = repository.ExecuteQueryDynamicallyAsync(query).Result;
            result = repository.ExecuteQueryStaticallyAsync<MeaningOfLifeQuery, int>(query).Result;

            // result = repository.ExecuteQueryStaticallyAsync(query).Result;
                // Doesn't work: type arguments cannot be inferred
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上我想让存储库只是通过调用ExecuteAsync方法并传递查询来执行查询.为了完成这项工作,我必须使用dynamic在运行时解析查询处理程序类型ExecuteQueryDynamicallyAsync.或者,我可以在调用方法时将查询类型和结果类型都指定为类型参数(按照ExecuteQueryStaticallyAsync),但这显然是一个冗长的调用,特别是当查询和/或返回类型具有长名称时.

我可以让编译器使用这样的方法签名来推断这两种类型:

Task<TResult> ExecuteQueryAsync<TQuery, TResult>(TQuery query, TResult ignored)
    where TQuery : class, IQuery<TResult>
Run Code Online (Sandbox Code Playgroud)

这允许我做这样的事情:

var query = new MeaningOfLifeQuery();
...
... ExecuteQueryAsync(query, default(int)) ...
Run Code Online (Sandbox Code Playgroud)

但是我必须在每次调用时将一个虚拟值(被忽略)传递给方法.将签名更改为:

Task<TResult> ExecuteQueryAsync<TQuery, TResult>(TQuery query, TResult ignored = default(TResult))
    where TQuery : class, IQuery<TResult>
Run Code Online (Sandbox Code Playgroud)

尝试避免在调用时传递值不起作用,因为编译器不能再推断结果类型(即返回到第一个).

关于如何解决这个问题,或者即使它是可以解决的,我有点不知所措.我唯一的选择似乎是坚持简单的调用语义(但必须依赖dynamic)或以某种方式改变我的架构.有什么方法可以得到我想要的调用语义吗?