Not clear behavior, if I declare type:
struct Token
{
public static implicit operator int(Token x)
{
return 0;
}
public static implicit operator string(Token x)
{
return "";
}
}
We have two implicit conversion. Work file if I use
var t = new Token();
if (t == "123")
{
}
CS0151: A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type
if I use:
switch (t)
{
case "123" :
{
break;
}
}
But if I remove int implicit conversion then error disappears.
struct Token
{
public static implicit operator string(Token x)
{
return "";
}
}
It is bug in compiler or correct behavior?
This is the correct behavior. From the spec, 8.7.2 The switch statement:
exactly one user-defined implicit conversion (Section 6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string. If no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.
We can also see the (next version) compiler source code that implements the spec at Conversions.UserDefinedImplicitConversions.
Note that I've removed some of the code and comments, this is just to get the general idea:
UserDefinedConversionResult? exactConversionResult = null;
foreach (UserDefinedConversionAnalysis analysis in u)
{
TypeSymbol tx = analysis.ToType;
if (tx.IsValidSwitchGoverningType(isTargetTypeOfUserDefinedOp: true))
{
if (!exactConversionResult.HasValue)
{
exactConversionResult = UserDefinedConversionResult.Valid(u, best.Value);
continue;
}
return UserDefinedConversionResult.Ambiguous(u);
}
}
// If there exists such unique TX in suitableTypes, then that operator is the
// resultant user defined conversion and TX is the resultant switch governing type.
// Otherwise we either have ambiguity or no applicable operators.
return exactConversionResult.HasValue ?
exactConversionResult.Value :
UserDefinedConversionResult.NoApplicableOperators(u);
Basically, the code iterates over the implicit conversions and keeps the first conversion it finds to a type that can appear in switch. If it finds another type it returns Ambiguous. If it finds exactly one type, it returns it.
Again, this is a short version of the code, the full code deals with more cases and barkwards compatibility.
The compiler's confusion seems to be understandable.
The switch statement can run on both int and string. You pass it a Token that contains implicit conversions to both. Which one should the compiler choose? It has no way to know which is preferred. Implicit constructors don't have priority.
In the if case, it's obvious you're comparing to a string, so that conversion is used. But the switch is ambiguous. The error isn't entirely clear, but I'm assuming that, not knowing which conversion to choose, it chooses neither, attempts to put the Token instance itself in the switch, and thus displays this error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With