Description
Existing compiler rules make that types that define implicit operators for string and string[] incur in a source breaking change.
Example:
class Program
{
static void Main()
{
var c = new C();
Join(",", c); // error CS0121: The call is ambiguous between the following methods or properties: 'Program.Join(string, params string[])' and 'Program.Join(string, params ReadOnlySpan<string>)'
}
public static string Join(string separator, params string[] value) => "array";
public static string Join(string separator, params ReadOnlySpan<string> value) => "span";
}
class C
{
public static implicit operator string(C c) => "c";
public static implicit operator string[](C c) => ["c"];
}
One real-world example is Microsoft.Extensions.Primitives.StringValues
which is passed into string.Join(string, string[])
on aspnetcore, and that it failed to compile when the changes in #100898 flowed into their repo.
API Proposal
Not quite a new API proposal, but a proposal for keeping as is the APIs on #77873.
These APIs would make existing callsites of their analogous params string[]
overloads to fail if a StringValues
is being passed as argument.
System.String.Concat(params ReadOnlySpan<string?> values)
System.String.Join(char separator, params ReadOnlySpan<string?> value)
System.String.Join(string? separator, params ReadOnlySpan<string?> value)
System.IO.Path.Combine(params ReadOnlySpan<string> paths)
System.IO.Path.Join(params ReadOnlySpan<string?> paths)
System.Text.StringBuilder.AppendJoin(string? separator, params ReadOnlySpan<string?> values)
System.Text.StringBuilder.AppendJoin(char separator, params ReadOnlySpan<string?> values)
Considering that having the ambiguity of string and string[] implicit operators feels like is against FDGs 5.7.2 Conversion Operators
DO NOT provide a conversion operator if such a conversion is not clearly expected by the end users.
I think the best path would be to accept the source breaking change and expect users to update their codebase, preferably picking the new ReadOnlySpan<string>
overloads.
Alternatively
@dotnet/roslyn could the compiler rules be adjusted to accommodate StringValues
? Why adding a public static implicit operator ReadonlySpan<string>
to StringValues
doesn't make the compiler select string.Join(string, ReadonlySpan<string>)
? It does make the error go away, though, by selecting the string[]
overload.