【问题标题】:Why can't these generic type parameters be inferred?为什么不能推断出这些泛型类型参数?
【发布时间】:2010-06-07 14:19:47
【问题描述】:

给定以下接口/类:

public interface IRequest<TResponse> { }

public interface IHandler<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    TResponse Handle(TRequest request);
}

public class HandlingService
{
    public TResponse Handle<TRequest, TResponse>(TRequest request)
        where TRequest : IRequest<TResponse>
    {
        var handler = container.GetInstance<IHandler<TRequest, TResponse>>();
        return handler.Handle(request);
    }
}

public class CustomerResponse
{
    public Customer Customer { get; set; }
}

public class GetCustomerByIdRequest : IRequest<CustomerResponse>
{
    public int CustomerId { get; set; }
}

如果我尝试编写如下内容,为什么编译器不能推断出正确的类型:

var service = new HandlingService();
var request = new GetCustomerByIdRequest { CustomerId = 1234 };
var response = service.Handle(request);  // Shouldn't this know that response is going to be CustomerResponse?

我刚刚收到“无法推断类型参数”消息。这是泛型类型推断的一般限制,还是有办法使这项工作发挥作用?

【问题讨论】:

    标签: c# generics inference


    【解决方案1】:

    您有约束TRequest : IRequest&lt;TResponse&gt;,但这并不意味着可以从TRequest 自动推断出TResponse。考虑到类可以实现多个接口,TRequest 可以实现 几个 IRequest&lt;TResponse&gt; 类型;您可能不会在自己的设计中这样做,但编译器必须在整个类层次结构中艰难地推断该特定参数会非常复杂。

    长话短说,Handle 方法采用 两个 泛型类型参数(TRequestTResponse),而您只给它一个可以实际使用的参数。推断仅发生在 实际 类型参数上,而不是它们继承或实现的类型。

    【讨论】:

    • 感谢 Aaronaught,我没有考虑过多个接口实现,这很有意义。然而,这让我认为这应该使它工作:IRequest&lt;CustomerResponse&gt; request = new GetCustomerByIdRequest {CustomerId = 1234}; 但它没有。当然,通过显式接口声明,TResponse 就没有歧义了吗?
    • @Jon:我明白你为什么会这么想,但不,这也不太行。传递一个抽象的IRequest&lt;TResponse&gt; 只保证特定的TResponse 满足约束;它无助于推断实际的TResponse 类型是什么(在评估约束之前必须知道它)。事实上,我不相信编译器在进行类型推断时根本不会考虑类型约束。它首先尝试推断类型,然后确保推断的类型满足约束。这就是为什么你不能重载仅因约束而不同的泛型方法。
    【解决方案2】:

    我认为这取决于使用情况...

    在这种情况下,某些东西(您没有在上面列出)正在调用 service.Handle(request);

    如果消费类在它自己的声明中不包含泛型类型,我想你会遇到这个问题。

    例如...(这行不通)

    public class MyClass
    {
         var service = new HandlingService();
         var request = new GetCustomerByIdRequest { CustomerId = 1234 };
         var response = service.Handle(request);
    }
    

    这应该可以工作...(该类需要知道 TResponse 是什么)

    public class MyClass<TResponse> where TResponse : YOURTYPE
    {
         var service = new HandlingService();
         var request = new GetCustomerByIdRequest { CustomerId = 1234 };
         var response = service.Handle(request);
    }
    

    【讨论】:

    • 我看不出这是如何工作的,TResponseMyClass&lt;TResponse&gt; 的上下文中与service.Handle 的推断类型参数没有关系,确定吗?
    猜你喜欢
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多