在.NET泛型方法不能有自己的返回类型推断。为什么?自己的、能有、推断、类型

2023-09-02 01:25:24 作者:含着泪微笑

由于:

static TDest Gimme<TSource,TDest>(TSource source) 
{ 
    return default(TDest); 
}

我为什么不能做的:

Why can't I do:

string dest = Gimme(5);

没有得到编译器错误:

without getting the compiler error:

错误CS0411:对方法的类型参数Whatever.Gimme&LT; TSource,TDest&GT;(TSource)'不能从使用推断。请尝试显式指定类型参数。

5 可以推断为 INT ,但有一个限制,其中编译器不会/罐牛逼解决的返回类型为字符串。我读过的几个地方的的这是由设计的,但没有真正的解释。我读的地方,这可能会改变在C#4,但它不是。

The 5 can be inferred as int, but there's a restriction where the compiler won't/can't resolve the return type as a string. I've read in several places that this is by design but no real explanation. I read somewhere that this might change in C# 4, but it hasn't.

谁知道为什么返回类型不能从一般的方法来推断?这是其中的一个问题,如果回答的这么明显它盯着你的脸?我希望不是!

Anyone know why return types cannot be inferred from generic methods? Is this one of those questions where the answer's so obvious it's staring you in the face? I hope not!

推荐答案

这里的一般原则是该类型信息流只有一条路,从的在的到的之外。你给的例子是非常简单的。假设我们希望有型信息流左右逢源的方法做类型推断,当 R G&LT; A,R&GT;(A一),并考虑到一些疯狂的场景创建:

The general principle here is that type information flows only "one way", from the inside to the outside of an expression. The example you give is extremely simple. Suppose we wanted to have type information flow "both ways" when doing type inference on a method R G<A, R>(A a), and consider some of the crazy scenarios that creates:

N(G(5))

假设有10个不同的重载的N,每一个不同的参数类型。我们应该使十个不同的推论的R?如果我们这样做,我们应该以某种方式挑选最好呢?

Suppose there are ten different overloads of N, each with a different argument type. Should we make ten different inferences for R? If we did, should we somehow pick the "best" one?

double x = b ? G(5) : 123;

我应该的G的返回类型推断为?诠释,因为条件前pression另一半为int?或者双,因为最终这件事情将被分配到两倍?现在,也许你开始看到这是如何去;如果你会说,你的理由,从外到内,多远你去的?有可能是的许多的沿途步骤。看看会发生什么,当我们开始结合这些:

What should the return type of G be inferred to be? Int, because the other half of the conditional expression is int? Or double, because ultimately this thing is going to be assigned to double? Now perhaps you begin to see how this goes; if you're going to say that you reason from outside to inside, how far out do you go? There could be many steps along the way. See what happens when we start to combine these:

N(b ? G(5) : 123)

现在我们怎么办?我们有N个10重载选择。我们说的是R为int?它可以是int或任何类型的int是隐式转换为。但是,这些类型的,哪些是隐式转换为N的参数类型的?难道我们自己写的一个小Prolog程序,并要求序言引擎解决什么是所有的R可能是为了满足每一个可能的过载对N,然后以某种方式挑选最好的一个可能的返回类型?

Now what do we do? We have ten overloads of N to choose from. Do we say that R is int? It could be int or any type that int is implicitly convertible to. But of those types, which ones are implicitly convertible to an argument type of N? Do we write ourselves a little prolog program and ask the prolog engine to solve what are all the possible return types that R could be in order to satisfy each of the possible overloads on N, and then somehow pick the best one?

(我不是在开玩笑;也有语言的本质的不的写一个小Prolog程序,然后使用一个逻辑引擎,以制定出什么一切的类型是F#例如,做的方式更复杂的类型推断比C#确实Haskell的类型系统实际上是图灵完备;你可以连接code的类型系统,并要求编译器任意复杂的问题,解决这些问题我们将在后面看到,同样是真正的重载在C#中 - 你不能连接code在C#类型系统的停机问题就像你在Haskell可以,但你可以连接code NP难问题,为重载问题)

(I'm not kidding; there are languages that essentially do write a little prolog program and then use a logic engine to work out what the types of everything are. F# for example, does way more complex type inference than C# does. Haskell's type system is actually Turing Complete; you can encode arbitrarily complex problems in the type system and ask the compiler to solve them. As we'll see later, the same is true of overload resolution in C# - you cannot encode the Halting Problem in the C# type system like you can in Haskell but you can encode NP-HARD problems into overload resolution problems.)

这是一个非常简单的EX pression。假设你有这样的事情

This is still a very simple expression. Suppose you had something like

N(N(b ? G(5) * G("hello") : 123));

现在我们已经解决了这个问题多次为G,并可能对于N还有,我们必须解决这些问题的组合的。我们有五个重载的问题需要解决和的所有的的他们,为了公平起见,应该同时考虑他们的观点和他们的上下文类型。如果有十个可能对于N则有可能一百年可能性考虑N(N(...))和千为N(N(N(...))),并很快你将有我们解决的问题,很容易有几十亿种可能的组合,并提出了编译器很慢。

Now we have to solve this problem multiple times for G, and possibly for N as well, and we have to solve them in combination. We have five overload resolution problems to solve and all of them, to be fair, should be considering both their arguments and their context type. If there are ten possibilities for N then there are potentially a hundred possibilities to consider for N(N(...)) and a thousand for N(N(N(...))) and very quickly you would have us solving problems that easily had billions of possible combinations and made the compiler very slow.

这就是为什么我们有这种类型的信息流只有一个办法规则。它prevents这些各种各样的鸡和蛋的问题,在这里你正试图确定这两个从内型外类型,并确定从外型内型,并导致一个可能性的组合爆炸。

This is why we have the rule that type information only flows one way. It prevents these sorts of chicken and egg problems, where you are trying to both determine the outer type from the inner type, and determine the inner type from the outer type and cause a combinatorial explosion of possibilities.

注意类型信息并为lambda表达式双向流动!如果你说 N(X =&GT; x.Length)然后果然,我们认为N个具有功能或EX pression类型所有可能的重载的参数,并尝试了所有可能的类型对于x。果然,there有些情况下,你可以很容易地使编译器尝试了数十亿可能的组合以找到独特结合的作品。类型推理规则,使它们能够做到这一点的一般方法是非常复杂的,赚乔恩斯基特紧张。 This功能使重载NP-HARD 。

Notice that type information does flow both ways for lambdas! If you say N(x=>x.Length) then sure enough, we consider all the possible overloads of N that have function or expression types in their arguments and try out all the possible types for x. And sure enough, there are situations in which you can easily make the compiler try out billions of possible combinations to find the unique combination that works. The type inference rules that make it possible to do that for generic methods are exceedingly complex and make even Jon Skeet nervous. This feature makes overload resolution NP-HARD.

获取类型信息双向流动的lambda表达式使通用重载工作正常,高效地花了大约一年的时间。这是一个复杂的功能,我们只希望把它。如果我们绝对肯定会对投资一个惊人的回报。使LINQ的工作是值得的。但是,有一个像LINQ没有相应的功能,证明使这项工作一般的巨大开支。

Getting type information to flow both ways for lambdas so that generic overload resolution works correctly and efficiently took me about a year. It is such a complex feature that we only wanted to take it on if we absolutely positively would have an amazing return on that investment. Making LINQ work was worth it. But there is no corresponding feature like LINQ that justifies the immense expense of making this work in general.

 
精彩推荐