关于PublicClientApplicationBuilder.WithParentActivityOrWindow方法调用歧义及VS2017与VS2019编译差异的技术咨询
WithParentActivityOrWindow(GetHandle)在VS2017编译失败,VS2019却可以? 你遇到的这个问题本质是C#语言版本差异导致的重载解析规则变化——VS2017默认使用C#7.2或更早版本,而VS2019默认支持C#7.3及以上,两者在处理方法组转换为泛型委托的逻辑上有明显区别。
1. C#7.3之前的重载解析逻辑(VS2017场景)
在C#7.3及更早的版本中,编译器将方法组(比如你的GetHandle)转换为泛型委托时,只会匹配参数列表,完全忽略返回类型。
看你的代码:
// 两个重载的参数列表都是无参,只有返回类型不同 static void WithParentActivityOrWindow(Func<IWin32Window> windowFunc) { } static void WithParentActivityOrWindow(Func<IntPtr> windowFunc) { } // 调用时传递方法组GetHandle WithParentActivityOrWindow(GetHandle);
编译器看到GetHandle是无参方法,会发现两个重载的委托参数(Func<IWin32Window>和Func<IntPtr>)都符合“无参”的要求,因为它不考虑返回类型,所以无法判断你要调用哪个重载,直接抛出歧义错误。
而当你改用lambda表达式() => GetHandle()时,编译器会先推断这个lambda的返回类型是IntPtr,然后直接匹配WithParentActivityOrWindow(Func<IntPtr>)这个重载,自然就没有歧义了。
2. C#7.3及之后的重载解析逻辑(VS2019场景)
C#7.3对方法组转换的重载解析做了优化:现在编译器会同时考虑委托的参数列表和返回类型。
对于你的调用WithParentActivityOrWindow(GetHandle),编译器会检查GetHandle的返回类型是IntPtr,然后直接匹配返回类型对应的Func<IntPtr>重载,完美避开歧义,所以能正常编译。
补充:带参数的方法为什么不会有歧义?
你提到的带参数的变体:
// 两个重载的参数类型不同 static void WithParentActivityOrWindow(Func<bool, IWin32Window> windowFunc) { } static void WithParentActivityOrWindow(Func<int, IntPtr> windowFunc) { } static IntPtr GetHandle(int) {} WithParentActivityOrWindow(GetHandle);
不管是哪个C#版本,编译器都会优先根据参数类型筛选重载。GetHandle的参数是int,只有Func<int, IntPtr>的参数列表匹配,所以编译器能直接确定调用哪个重载,不会出现歧义。
内容的提问来源于stack exchange,提问作者oleksa

