Reputation: 73
I'm on a team with two other devs. For the past few months I've been working on a project in C# 12 independently, and only recently have the other devs pulled my code and run it. For one of them it worked fine, but the other faced a compilation error, CS0121, in the following context.
I have a class with two constructors. One constructor takes a string; the other takes an IEnumerable
of data (instances of a record type). This class also has a public static readonly
field None
that wraps an empty collection of data:
public static readonly Foo None = new([]);
For myself and Colleague A, this code compiled without problem. But Colleague B could not compile the code because of a CS0121 error that the call was ambiguous between the two constructors:
The call is ambiguous between the following methods or properties: 'Foo.Foo(IEnumerable)' and 'Foo.Foo(string)'.
Colleague B changed the line to
public static readonly Foo None = new(Array.Empty<Bar>());
and was then able to compile the code.
We verified that, for all three of us, the code was set to target C# 12 and .NET 8.0
Any guesses as to what could be going on? For a hot second I wondered whether it had anything to do with breaking changes in C# 13 involving collection expressions, but we're all on C# 12, so it can't be that.
One of the comments below suggested this may be a duplicate of this question. As suggested in that question, I downgraded my SDK to 8.0.201, but was still able to compile successfully.
Here is some dummy code that mimics the issue we were having - though since I can't reproduce the error on my machine it's possible I'm missing some nuance here that causes the issue.
using System.Diagnostics;
namespace Foobar;
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Running on SDK " + GetSdkVersion()); // compiles using either SDK 8.0.201 or 9.0.100
Foo none = Foo.None;
Console.WriteLine(none.ToString()); // prints "Foo: [ (from Bar constructor)]"
Bar[] helloWorldBars = ["hello", "world"];
Foo helloWorldFoo = new(helloWorldBars);
Console.WriteLine(helloWorldFoo.ToString()); // prints "Foo: [(hello),(world) (from Bar constructor)]"
Foo fromString = new("spam");
Console.WriteLine(fromString.ToString()); // prints "Foo: [spam (from string constructor)]"
Console.Write("Press ENTER to quit.");
Console.ReadLine();
}
private static string GetSdkVersion()
{
// https://stackoverflow.com/questions/70960644/how-to-programmatically-check-the-net-sdk-version
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() ?? "UNKONWN";
process.WaitForExit();
return version;
}
}
public class Foo
{
private readonly string fooData;
/// <summary>Returns a <see cref="Foo"/> constructed from an empty <see cref="Bar"/> collection</summary>
public static readonly Foo None = new([]); // CS0121: The call is ambiguous for one of my colleagues
// public static readonly Foo None = new(Array.Empty<Bar>()); // unambiguous alternative
/// <summary>Construct a <see cref="Foo"/> from a string</summary>
public Foo(string fooData)
{
this.fooData = fooData + " (from string constructor)";
}
/// <summary>Construct a <see cref="Foo"/> from a collection of <see cref="Bar"/>s</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);
}
And my global.json
file:
{
"sdk": {
"version": "8.0.201",
"rollForward": "disable"
}
}
Upvotes: 1
Views: 49