C# 12环境下集合初始化器引发CS0121歧义调用问题求助
我最近碰到个特别费解的问题,想请大家帮忙捋捋:我和另外两位开发者组队做项目,过去几个月我独自用C# 12开发了一个模块,最近两位同事拉取代码后,一位编译运行都正常,另一位却直接碰到了CS0121(调用歧义)的编译错误。
先给大家说下核心的代码场景:我定义了一个Foo类,有两个构造函数——一个接收string参数,另一个接收IEnumerable<Bar>(Bar是一个带隐式字符串转换的记录类型)。同时类里还有个public static readonly的None字段,用来包装一个空的Bar集合,代码是这样的:
public static readonly Foo None = new([]);
我和同事A的环境里这段代码完全能正常编译,但同事B那边直接报了CS0121错误,提示内容是:
The call is ambiguous between the following methods or properties:
'Foo.Foo(IEnumerable)' and 'Foo.Foo(string)'.
同事B把代码改成下面这样后,就顺利编译通过了:
public static readonly Foo None = new(Array.Empty<Bar>());
我们三个人都反复确认过,项目的目标框架都是C# 12和**.NET 8.0**。我一开始还怀疑是不是C#13里集合表达式的破坏性变更,但我们明明都锁定了C#12,肯定不是这个原因。后来我还按照类似问题的建议,把自己的SDK降级到8.0.201,代码还是能正常编译,完全复现不出同事B的错误。
下面是我写的模拟问题的测试代码(虽然我自己这边跑不出来错误,但尽量还原了真实场景):
using System.Diagnostics; using System.Linq; namespace Foobar; internal class Program { static void Main(string[] args) { Console.WriteLine("Running on SDK " + GetSdkVersion()); // 无论用8.0.201还是9.0.100都能编译 Foo none = Foo.None; Console.WriteLine(none.ToString()); // 输出 "Foo: [ (from Bar constructor)]" Bar[] helloWorldBars = ["hello", "world"]; Foo helloWorldFoo = new(helloWorldBars); Console.WriteLine(helloWorldFoo.ToString()); // 输出 "Foo: [(hello),(world) (from Bar constructor)]" Foo fromString = new("spam"); Console.WriteLine(fromString.ToString()); // 输出 "Foo: [spam (from string constructor)]" Console.Write("Press ENTER to quit."); Console.ReadLine(); } private static string GetSdkVersion() { Process process = new(); process.StartInfo.FileName = "dotnet.exe"; process.StartInfo.Arguments = "--version"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.Start(); string version = process.StandardOutput.ReadToEnd()?.TrimEnd() ?? "UNKNOWN"; process.WaitForExit(); return version; } } public class Foo { private readonly string fooData; /// <summary>返回包装空Bar集合的Foo实例</summary> public static readonly Foo None = new([]); // 同事B编译时触发CS0121错误 // public static readonly Foo None = new(Array.Empty<Bar>()); // 无歧义的替代写法 /// <summary>用字符串构造Foo</summary> public Foo(string fooData) { this.fooData = fooData + " (from string constructor)"; } /// <summary>用Bar集合构造Foo</summary> public Foo(IEnumerable<Bar> bars) { this.fooData = string.Join(',', bars.Select(b => $"({b})")) + $" (from {nameof(Bar)} constructor)"; } public override string ToString() => $"{nameof(Foo)}: [{fooData}]"; } public record Bar(string BarData) { public override string ToString() => BarData; public static implicit operator Bar(string barData) => new(barData); }
还有我的global.json配置:
{ "sdk": { "version": "8.0.201", "rollForward": "disable" } }
有没有大佬能帮忙分析下这到底是怎么回事啊?实在想不通为什么相同的目标框架和语言版本下,三个人的编译结果会不一样...
备注:内容来源于stack exchange,提问作者mdirks

