【发布时间】:2016-07-25 22:10:31
【问题描述】:
我无法让编译器解决扩展方法的正确重载问题。对我来说最好的解释方法是使用一些代码。这是一个演示问题的LINQPad 脚本。由于我遇到的问题,这不会编译:
void Main(){
new Container<A>().Foo(a=>false);
}
interface IMarker{}
class A : IMarker{
public int AProp{get;set;}
}
class B : IMarker{
public int BProp{get;set;}
}
class Container<T>{}
static class Extensions{
public static void Foo<T>(this T t, Func<T, bool> func)
where T : IMarker{
string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Foo<T>(this Container<T> t, Func<T, bool> func){
string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
}
}
我得到的错误是:
以下方法或属性之间的调用不明确:“
Extensions.Foo<Container<A>>(Container<A>, System.Func<Container<A>,bool>)”和“Extensions.Foo<A>(Container<A>, System.Func<A,bool>)”
在我看来,它一点也不含糊。第一种方法不接受Container<T>,只接受IMarker。似乎通用约束没有帮助解决重载问题,但在这个版本的代码中,它们似乎是:
void Main(){
new A().Bar();
new A().Foo(a=>a.AProp == 0);
new A().Foo(a=>false); // even this works
new A().Foo(a=>{
var x = a.AProp + 1;
return false;
});
new Container<A>().Bar();
new Container<A>().Foo(a=>a.AProp == 0);
new Container<A>().Foo(a=>{
var x = a.AProp + 1;
return false;
});
}
interface IMarker{}
class A : IMarker{
public int AProp{get;set;}
}
class B : IMarker{
public int BProp{get;set;}
}
class Container<T>{}
static class Extensions{
public static void Foo<T>(this T t, Func<T, bool> func)
where T : IMarker{
string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Foo<T>(this Container<T> t, Func<T, bool> func){
string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
}
public static void Bar<T>(this T t) where T : IMarker{
string.Format("Bar({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Bar<T>(this Container<T> t){
string.Format("Bar(Container<{0}>)", typeof(T).Name).Dump();
}
}
这会编译并产生预期的结果:
条形图(A:IMarker)
Foo(A:IMarker)
Foo(A:IMarker)
Foo(A:IMarker)
酒吧(容器)
Foo(容器)
Foo(容器)
似乎只有当我没有在 lambda 表达式中引用 lambda 参数时才有问题,然后才使用 Container<T> 类。在调用Bar 时,没有 lambda,它工作正常。当使用基于 lambda 参数的返回值调用 Foo 时,它工作正常。即使 lambda 的返回值与示例中未编译的返回值相同,但 lambda 参数被虚拟赋值引用,它仍然有效。
为什么它在这些情况下有效,但在第一种情况下无效?我做错了什么,还是我发现了编译器错误?我已经确认了 C# 4 和 C# 6 中的行为。
【问题讨论】:
-
@ManoDestra:编辑是因为你不喜欢我放置花括号的位置。
-
这是 C#。因此进行了编辑。
-
我不明白你的意思。
-
一方面,该文档没有定义大括号的位置。第二,那是一套指导方针,而不是严格的规则。三,你不是风格警察。四个人,请去拖钓别人,不要试图强迫我的代码适合你的个人口味。
标签: c# extension-methods overload-resolution