为什么 C# 不推断我的泛型类型? [英] Why doesn't C# infer my generic types?

查看:31
本文介绍了为什么 C# 不推断我的泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对泛型方法有很多有趣的乐趣(有意的).在大多数情况下,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?

代码如下:

类和接口定义:

interface IQuery<TResult> { }

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

class SomeQuery : IQuery<string>
{
}

一些无法编译的代码:

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:

  1. 我提供了一个实现 IQuery 的对象.
  2. 类型实现的唯一 IQuery 版本是 IQuery,因此 TResult 必须是 string.
  3. 有了这些信息,编译器就有了 TResult 和 TQuery.
  1. I supply an object that implements IQuery<TResult>.
  2. That only IQuery<TResult> version that type implements is IQuery<string> and thus TResult must be string.
  3. 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 参数.这样它就可以返回一个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:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/c-3-0-return-type-in​​ference-does-not-work-on-method-组

那篇文章已经过时且与问题无关.它已经过时,因为它描述了我们在 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:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/constraints-are-not-part-of-the-signature

更新:我听说C# 7.3 稍微改变了应用约束的规则,使得上面十年前的文章不再准确.当我有时间时,我会回顾我以前的同事所做的更改,看看是否值得在我的新博客上发表更正;在此之前,请谨慎使用并查看 C# 7.3 在实践中的作用.

UPDATE: I have heard news that C# 7.3 has slightly changed the rules for when constraints are applied, making the above ten-year-old article no longer accurate. When I have time I'll review the changes my former colleagues have made and see if it is worthwhile to post a correction on my new blog; until then, use caution and see what C# 7.3 does in practice.

这篇关于为什么 C# 不推断我的泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆