鉴于以下课程:
Point 3D-W :
[0.003070864657310213;
0.0004761913292736786;
0.06461112415423849]
第二次调用Point 3D-W Normalized =
[0.003070864657310213 / 0.06461112415423849;
0.0004761913292736786 / 0.06461112415423849;
0.06461112415423849 / 0.06461112415423849]
时出现编译错误,抱怨没有从Point 3D-W Normalized =
[0.047528420183179314;
0.007370113668614144;
1.0]
转换为public static class MWE
{
public static void Foo<T, TColl>(Expression<Func<IFoo, bool>> bar, TColl foos)
where TColl : IEnumerable<T>
{
}
public static void Foo<T, TColl>(Expression<Func<IFoo, T>> bar, TColl foos)
where TColl : IEnumerable<T>
{
}
static MWE()
{
Foo(bar => bar.GetThing(), new List<IThing>());
Foo(bar => bar.GetBool(), new List<IThing>());
}
}
public interface IFoo
{
IThing GetThing();
bool GetBool();
}
。在我看来,编译器没有看到第一个重载,虽然它匹配(而第二个没有)。
为什么呢?有两种方法可以共存和工作吗?
答案 0 :(得分:2)
无法调用第一个重载,因为没有足够的信息来推断泛型参数。您使用一个的通用参数TColl
,但您从不在签名中使用T
,因此无法推断它。
如果您明确指定了泛型参数,那么将选择第一个重载并且它将正常工作。
如果您只是完全删除第二个泛型参数,并在签名中使用IEnumerable<T>
而不是TColl
,则会简化这些方法,并允许两个现有调用正常运行。
答案 1 :(得分:2)
通用类型约束(where ...
)不用于泛型类型推断(当您没有明确说明它们时推断T
和TCall
)。您可能认为第一次重载中的T
类型可能会被推断为IThing
,因为您将List<IThing>
作为TColl
传递,但由于上述情况,情况并非如此。
由于无法推断泛型类型 - 此方法不参与重载解析,因此使用第二种方法。失败了,你看到了编译错误。
答案 2 :(得分:0)
首先看一下这个:
public static void Foo<T, TColl>(Expression<Func<IFoo, T>> bar, TColl foos)
where TColl : IEnumerable<T>
编译器如何确定T
是什么?它会查看您传递的表达式(bar
)并查看返回类型。从那以后,它可以推断T
。 bar
会返回IThing
,因此T
为IThing
而TColl
为IEnumerable<IThing>
。
现在看看这个:
public static void Foo<T, TColl>(Expression<Func<IFoo, bool>> bar, TColl foos)
where TColl : IEnumerable<T>
T
是什么?它不是bar
返回的类型,它被硬编码为bool
。那是什么?编译器无法分辨,因此您可以使用此函数的唯一方法是显式地告诉它通用参数是什么:
Foo<IThing,List<IThing>>(bar => bar.GetBool(), new List<IThing>());
^这将编译。
无法弄清楚T
是什么,它必须使用第一个函数,推断T
是bool
然后它会抱怨因为你传递了IEnumerable<IThing>
IEnumerable<bool>
1}}何时需要SELECT * FROM DUAL