泛型、重载解析和委托(抱歉,找不到更好的标题)

发布于 2024-10-10 05:50:46 字数 1917 浏览 7 评论 0 原文

可能的重复:
为什么 Func与 Func> 不明确?

我注意到泛型有一个非常奇怪的重载解析问题...

考虑以下方法:

static void Foo<TSource>(TSource element, Func<TSource, int> selector)
{
    "int".Dump();
}

static void Foo<TSource>(TSource element, Func<TSource, double> selector)
{
    "double".Dump();
}

static T Identity<T>(T value)
{
    return value;
}

(C# 4,在 LINQPad 中测试)

如果我尝试调用 Foo 使用 lambda 表达式作为选择器,一切正常:

Foo(42, x => x); // prints "int"

但是如果我替换 x =>; xIdentity 时,编译器无法在 2 个 Foo 重载之间做出决定:

Foo(42, Identity);
// The call is ambiguous between the following methods or properties:
// 'UserQuery.Foo<int>(int, System.Func<int,int>)' and
// 'UserQuery.Foo<int>(int, System.Func<int,double>)'

第二个重载如何成为有效候选者?类型推断正确确定 TSourceint,因此 Identity 方法的 T 参数必须为 >int 也是如此,因此返回类型也必须是 int...Identity 可以是 FuncFunc code> 或 Func,但不是 Func

而且情况变得更糟!即使我显式指定所有类型参数,我仍然会得到相同的错误:

Foo<int>(42, Identity<int>); // The call is ambiguous...

这里怎么可能有任何歧义?据我所知,采用 Func 的重载不可能成为候选者。我想解释一定在规范中的某个地方,但我找不到相关的位......或者它可能是编译器中的错误,但我想这不太可能。

请注意,如果我显式创建委托,它确实有效:

Foo(42, new Func<int, int>(Identity)); // prints "int"

那么,有人可以解释一下这里发生了什么吗?另外,为什么它可以与 lambda 一起使用,但不能与方法组一起使用?

Possible Duplicate:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?

I noticed a very weird overload resolution issue with generics...

Consider the following methods:

static void Foo<TSource>(TSource element, Func<TSource, int> selector)
{
    "int".Dump();
}

static void Foo<TSource>(TSource element, Func<TSource, double> selector)
{
    "double".Dump();
}

static T Identity<T>(T value)
{
    return value;
}

(C# 4, tested in LINQPad)

If I try to call Foo with a lambda expression as the selector, everything works fine:

Foo(42, x => x); // prints "int"

But if I replace x => x with Identity, the compiler can't decide between the 2 Foo overloads:

Foo(42, Identity);
// The call is ambiguous between the following methods or properties:
// 'UserQuery.Foo<int>(int, System.Func<int,int>)' and
// 'UserQuery.Foo<int>(int, System.Func<int,double>)'

How can the second overload be a valid candidate ? Type inference correctly determines that TSource is int, so the T parameter for the Identity method has to be int as well, so the return type has to be int too... Identity could be a Func<int,int> or a Func<double,double>, but not a Func<int,double>!

And it gets worse! Even if I specify all type parameters explicitly, I still get the same error:

Foo<int>(42, Identity<int>); // The call is ambiguous...

How can there be any ambiguity here? As far as I can tell, there is no way the overload that takes a Func<int,double> can be a candidate. I guess the explanation must be somewhere in the specifications, but I can't find the relevant bit... or it might be a bug in the compiler, but I guess it's unlikely.

Note that it does work if I explicitly create the delegate:

Foo(42, new Func<int, int>(Identity)); // prints "int"

So, could someone explain what's going on here? Also, why does it work with a lambda but not with a method group?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橘香 2024-10-17 05:50:46

这难道不是因为返回类型不是方法签名的一部分吗?

编译器在尝试决定使用哪个 Foo 重载时,并未考虑 Identity 方法的参数类型和返回类型保证相同的事实。 是必需的。如果不考虑返回类型,则 Identity 同样可以转换为 FuncFunc code> 或 Func

Isn't it simply because the return type isn't part of the method's signature?

The fact that the Identity<T> method's argument type and return type are guaranteed to be the same isn't taken into account by the compiler when attempting to decide which overload of Foo<TSource> is required. If the return type isn't considered then Identity<int> could equally be convertible to Func<int, int>, Func<int, double> or Func<int, anything>.

静若繁花 2024-10-17 05:50:46

我认为 LukeH 是正确的。但是,要回答您问题的第二位:lambda 的委托已经填充了所有类型(例如,如果 TSource 则始终为 Func是一个int),这就是为什么在这种情况下没有歧义。它不像函数签名那样忽略返回类型。

I think that LukeH is correct. However, to answer the second bit of your question: the delegate of the lambda will already have all types filled in (e.g. always be a Func<int, int> if TSource is an int), which is why there is no ambiguity in that case. It's not like a function signature where the return type is ignored.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文