为什么不是C#我的推断泛型类型?我的、推断、类型、不是

2023-09-02 01:35:48 作者:你看上去好像很好吃

我有很多的Funcy好玩(FUN意)与泛型方法。在大多数情况下,C#的类型推断是足够聪明,找出通用的参数必须在我的泛型方法使用,但现在我已经有了一个设计,其中C#编译器不会成功,但我相信它会成功地找到正确的类型。

I'm having lots of Funcy fun (fun intended) with generic methods. In most cases C# type inference is smart enough to find out what generic arguments it must use on my generic methods, but now I've got a design where the C# compiler doesn't succeed, while I believe it could have succeeded in finding the correct types.

谁能告诉我该编译器是否有点哑在这种情况下,还是有一个很明显的原因,也不能推断出我的通用参数?

Can anyone tell me whether the compiler is a bit dumb in this case, or is there a very clear reason why it can't infer my generic arguments?

这里的code:

类和接口定义:

interface IQuery<TResult> { }

interface IQueryProcessor
{
    TResult Process<TQuery, TResult>(TQuery query)
        where TQuery : IQuery<TResult>;
}

class SomeQuery : IQuery<string>
{
}

有些code无法编译:

Some code that does not compile:

class Test
{
    void Test(IQueryProcessor p)
    {
        var query = new SomeQuery();

        // Does not compile :-(
        p.Process(query);

        // Must explicitly write all arguments
        p.Process<SomeQuery, string>(query);
    }
}

这是为什么?我缺少的是在这里吗?

Why is this? What am I missing here?

下面是编译器的错误信息(它不会留下太多的我们的想象):

Here's the compiler error message (it doesn't leave much to our imagination):

有关方法IQueryProcessor.Process的类型参数(的TQuery)不能从使用推断。尝试指定   明确类型的参数。

The type arguments for method IQueryProcessor.Process(TQuery) cannot be inferred from the usage. Try specifying the type arguments explicitly.

究其原因,我相信C#应该可以推断这是由于下列原因:

The reason I believe C# should be able to infer it is because of the following:

在我提供一个对象,它实现 IQUERY&LT; TResult&GT; 这仅 IQUERY&LT; TResult&GT; 版本类型实现是 IQUERY&LT;字符串&GT; ,因此TResult必须字符串。 有了这些信息,编译器TResult和TQuery的。 I supply an object that implements IQuery<TResult>. That only IQuery<TResult> version that type implements is IQuery<string> and thus TResult must be string. With this information the compiler has TResult and TQuery.

解决方案:

对我来说,最好的解决办法是改变 IQueryProcessor ​​接口,并使用动态类型的实现:

For me the best solution was to change the IQueryProcessor interface and use dynamic typing in the implementation:

public interface IQueryProcessor
{
    TResult Process<TResult>(IQuery<TResult> query);
}

// Implementation
sealed class QueryProcessor : IQueryProcessor {
    private readonly Container container;

    public QueryProcessor(Container container) {
        this.container = container;
    }

    public TResult Process<TResult>(IQuery<TResult> query) {
        var handlerType =
            typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
        dynamic handler = container.GetInstance(handlerType);
        return handler.Handle((dynamic)query);
    }
}

IQueryProcessor ​​接口,现在只需在一个 IQUERY&LT; TResult&GT; 参数。这样,它可以返回一个 TResult ,这将解决从消费者的角度来看问题。我们需要使用反射在实施中得到实际落实,因为需要具体的查询类型(对我来说)。但这里来动态类型到会做了反思我们的救援。您可以在此文章阅读更多关于这一点。

The IQueryProcessor interface now takes in a IQuery<TResult> parameter. This way it can return a TResult and this will solve the problems from the consumer's perspective. We need to use reflection in the implementation to get the actual implementation, since the concrete query types are needed (in my case). But here comes dynamic typing to the rescue which will do the reflection for us. You can read more about this in this article.

推荐答案

一堆人指出,C#不作出基于约束的推论。这是正确的,而相关的问题。推论通过检查做出的参数的和其相应的形参类型的,这是推理信息的唯一来源。

A bunch of people have pointed out that C# does not make inferences based on constraints. That is correct, and relevant to the question. Inferences are made by examining arguments and their corresponding formal parameter types and that is the only source of inference information.

一堆人都再联系到这篇文章:

A bunch of people have then linked to this article:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

这条既出过期和不相关的问题。这是外的日期,因为它描述了一个设计决策,我们建立在C#3.0中,我们则扭转了C#4.0,主要是基于响应该文章。我刚刚添加了一个更新的影响的文章。

That article is both out-of-date and irrelevant to the question. It is out-of-date because it describes a design decision we made in C# 3.0 which we then reversed in C# 4.0, mostly based on the response to that article. I've just added an update to that effect to the article.

这是无关紧要的,因为文章是关于的返回类型推断的方法组参数泛型委托形式参数的。这不是原来的海报询问有关情况。

It is irrelevant because the article is about return type inference from method group arguments to generic delegate formal parameters. That is not the situation the original poster asks about.

我的相关文章阅读是相当这一个:

The relevant article of mine to read is rather this one:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx