VS2019 Roslyn编译器通用约束方法解析

joh*_*y 5 2 c# roslyn

我们最近在代码库中发现了一个问题,其中VS2019编译的代码很好,但VS 2017失败。

我为Union创建了一个扩展方法,该方法具有一个通用ISet作为通用约束

using System;
using System.Collections.Generic;
using System.Linq;
public static class Extensions
{
    public static S Union<S, T>(this S self, IEnumerable<T> other) where S : ISet<T>, new()
    {
        //For simplicity issues since this is a compilation based question
        return default(S);
    }

    public static void Test()
    {
        var values = new[] { 1, 2, 3 };
        var values1 = new[] { 1, 2, 3, 4 };

        values.Union(values1);
    }
}
Run Code Online (Sandbox Code Playgroud)

Union生成编译错误,指出int []无法转换为ISet。

据我了解,方法解析最初忽略了通用约束。但似乎这段代码会在2019年编译。

我没有在发行说明中看到任何地方,它们指出他们已经解决了该错误或添加了新功能来改善通用方法的方法分辨率。

我正在寻找有关此问题的更多信息,这是Microsoft的错误修复程序还是预期的功能?

Jon*_*eet 5

它是C#7.3的一部分(因此,如果您指定7.3版,则也可以在VS 2017中使用它)。它记录在C#7.3发行说明中

改进的过载候选

在每个版本中,过载解决规则都会更新,以解决模棱两可的方法调用具有“明显”选择的情况。此版本添加了三个新规则,以帮助编译器选择显而易见的选择:

  1. ...
  2. 当方法组包含某些类型参数不满足其约束的通用方法时,这些成员将从候选集中删除。
  3. ...

这不是以前的错误-遵守语言规范;我不知道为什么规范最初是按照这里的方式编写的。可能的原因包括:

  • 预期的实施复杂性
  • 预期的实施绩效
  • 预期的有用性-预期先前的行为会比当前的行为好甚至更好,而不会意识到现实中会令人讨厌的地方

  • 这是第三。我们知道这不是“避免复杂性”,因为无论哪种方式,实现都必须检测到错误情况并产生明智的错误消息。如果我们在检查通用约束违规的那一点走动,该算法就不会或多或少复杂。而且没有性能上的胜利;方法组很小。 (2认同)
  • 提出的论据是:如果重载解析忽略了约束并推论出*给定参数的最佳方法*是违反约束的方法,那么很可能开发人员要么有错误的论据,要么认为推断出了*应该*满足约束条件;在这种情况下,正确的做法是通知开发人员有关其约束的错误论点或错误信念。因此,约束检查处于“最终验证”阶段,而不是“删除不适用的候选者”阶段。 (2认同)
  • 如果您看一下Roslyn中的重载解决方案代码,您会发现我写了它,以便重载解决方案不只是产生最佳方法。而是生成一份报告,描述描述了所考虑的每种方法以及拒绝该方法的原因。然后,该报告是错误消息生成器的输入。当我试图弄清为什么重载解决方案选择错误的方法或给出错误的错误时,在调试器中提供该报告非常有用。我的意图是在Roslyn API中公开它,但我不知道是否曾经发生过。 (2认同)