Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以';在这种重载解析情况下,编译器不能告诉更好的转换目标吗?(协方差)_C#_Delegates_Covariance_Overloading_Overload Resolution - Fatal编程技术网

C# 为什么可以';在这种重载解析情况下,编译器不能告诉更好的转换目标吗?(协方差)

C# 为什么可以';在这种重载解析情况下,编译器不能告诉更好的转换目标吗?(协方差),c#,delegates,covariance,overloading,overload-resolution,C#,Delegates,Covariance,Overloading,Overload Resolution,理解关于重载解析的C#语言规范显然很难,现在我想知道为什么这个简单的例子失败了: void Method(Func<string> f) { } void Method(Func<object> f) { } void Call() { Method(() => { throw new NotSupportedException(); }); } 嗯,你说得对。这里出现问题的原因是您作为参数传递的委托。它没有显式的返回类型,您只是抛出了一个异常异常基本上是

理解关于重载解析的C#语言规范显然很难,现在我想知道为什么这个简单的例子失败了:

void Method(Func<string> f)
{
}
void Method(Func<object> f)
{
}
void Call()
{
    Method(() => { throw new NotSupportedException(); });
}

嗯,你说得对。这里出现问题的原因是您作为参数传递的委托。它没有显式的返回类型,您只是抛出了一个异常<代码>异常基本上是一个
对象
,但它不被视为方法的返回类型。因为在异常抛出之后没有返回调用,所以编译器不确定应该使用什么重载

试试这个

void Call()
{
    Method(() => 
    { 
        throw new NotSupportedException();
        return "";
    });
}
现在选择重载没有问题,因为传递给返回调用的对象的类型是显式声明的。由于异常抛出而无法访问返回调用并不重要,但现在编译器知道应该使用什么重载

编辑:

至于传递null的情况,我不知道答案

我的问题很简单:我在这里遗漏了C#规范的哪一部分

总结:
  • 您在实现中发现了一个已知的小错误
  • 出于向后兼容的原因,将保留该错误
  • C#3规范包含一个关于如何处理“null”案例的错误;它是在C#4规范中固定的
  • 您可以在无法推断返回类型的任何lambda中复制错误行为。例如:
    Method(()=>null)
细节: C#5规范规定,更好的规则是:

  • 如果表达式具有类型,则选择从该类型到候选参数类型的更好转换

  • 如果表达式没有类型且不是lambda,请选择转换为更好的类型

  • < P>若表达式为λ,则首先考虑哪种参数类型更好;如果两者都不好,并且委托类型具有相同的参数列表,那么考虑lambda的推断返回类型与委托的返回类型之间的关系。

因此,预期的行为是:首先,编译器应该检查一种参数类型是否明显优于另一种,而不管参数是否具有类型。如果这不能解决这种情况,并且参数是lambda,则检查转换为参数“delegate types”返回类型的推断返回类型是否更好

实现中的错误在于实现没有做到这一点。相反,在参数为lambda的情况下,它完全跳过类型betterness检查,直接进入推断返回类型betterness检查,该检查随后失败,因为没有推断返回类型

我的目的是为Roslyn解决这个问题。然而,当我去实现它时,我们发现进行修复会导致一些实际代码停止编译。(我不记得真实世界的代码是什么,我不再有权访问包含兼容性问题的数据库。)因此,我们决定保留现有的小错误

我注意到,在我将委托差异添加到C#4之前,这个错误基本上是不可能的;在C#3中,两种不同的委托类型不可能有或多或少的特定性,因此唯一可以应用的规则是lambda规则。由于在C#3中没有任何测试会揭示错误,因此编写起来很容易。我的错,对不起

我还注意到,当您开始将表达式树类型添加到混合中时,分析会变得更加复杂。即使
Func
优于
Func
Expression
也不能转换为
Expression
!如果betterness算法对于lambda是指向表达式树还是委托是不可知的,那就好了,但在某些方面不是。这些案件变得复杂起来,我不想在这里赘述


这个小错误是一个关于实现规范实际所说内容而不是您认为它所说内容的重要性的对象课程。如果我在C#3中更加小心地确保代码与规范匹配,那么代码在“null”情况下就会失败,并且在早些时候就会清楚C#3规范是错误的。实现在类型检查之前进行lambda检查,这是一个定时炸弹,当C#4启动时,它会突然变成错误代码。无论如何,类型检查应该先完成

PS!这很好:
void Test(Func f1,Func f2,bool b){var x=b?f1:f2;}
我不能确定它,但它可能与这篇文章有关:在这里,Eric解释说函数永远不会到达它们的端点,或者任何返回实际上都没有任何返回值。因此,如果lambda是Func类型,我假设编译器会选择第一个方法而不是第二个方法。但它属于“未知类型”。以某种方式呃……)@Imi lambda本身没有委托(或表达式树)类型。对于我的lambda,也找不到返回类型。但是我的lambda肯定可以隐式转换为
Func
。我的lambda也可以隐式转换为
Func
。因此,这两种重载都是“适用的”。现在,一个比另一个好吗?是的,因为
Func
是比
Func
更好的转换目标。另请参见我对问题的补充(文本
null
本身没有类型,但是
null
可以隐式转换为
Func
Func
)。它正确选择
null
的事实表明7.5.3.5更好的转换目标得到了正确遵守。也许在7.5.3.3中有一个问题,从表达式或之前更好地转换。我本打算在阅读说明书的过程中发布一个答案,但我想我可以说,我认为你是对的
void Call()
{
    Method(() => 
    { 
        throw new NotSupportedException();
        return "";
    });
}