C# 结合使用隐式转换运算符和开关
不清楚行为,如果我声明类型:C# 结合使用隐式转换运算符和开关,c#,C#,不清楚行为,如果我声明类型: struct Token { public static implicit operator int(Token x) { return 0; } public static implicit operator string(Token x) { return ""; } } 我们有两个隐式转换。 工作文件,如果我使用 var t = new Token(); if (t == "
struct Token
{
public static implicit operator int(Token x)
{
return 0;
}
public static implicit operator string(Token x)
{
return "";
}
}
我们有两个隐式转换。
工作文件,如果我使用
var t = new Token();
if (t == "123")
{
}
CS0151:开关表达式或大小写标签必须是bool、char、string、integral、enum或相应的可空类型
如果我使用:
switch (t)
{
case "123" :
{
break;
}
}
但若我删除int隐式转换,那个么错误就会消失
struct Token
{
public static implicit operator string(Token x)
{
return "";
}
}
这是编译器中的错误还是正确的行为?编译器的困惑似乎是可以理解的。
switch
语句可以在int
和string
上运行。您向它传递一个令牌
,该令牌包含对两者的隐式转换。编译器应该选择哪一个?它无法知道哪个是首选。隐式构造函数没有优先级
在
if
的情况下,很明显您是在比较字符串,因此使用了转换。但这种转变是不明确的。错误并不完全清楚,但我假设,在不知道要选择哪种转换时,它会尝试将令牌
实例本身放入交换机中,从而显示此错误。这是正确的行为,因为开关
语句不知道要将t
转换为什么类型:
switch (t)
{
case "123" :
break;
case 0:
break;
}
这应该很清楚,因为t
不能转换为int
和string
,但以下操作有效:
switch ((string)t)
{
case "123" :
break;
}
现在,您可以清楚地定义要切换字符串…这是正确的行为。根据规范: 从开关表达式的类型到以下可能的控制类型之一,必须存在一个用户定义的隐式转换():sbyte、byte、short、ushort、int、uint、long、ulong、char、string。如果不存在此类隐式转换,或者存在多个此类隐式转换,则会发生编译时错误
我们还可以在上看到实现规范的(下一版本)编译器源代码。
请注意,我已经删除了一些代码和注释,这只是为了获得总体思路:
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);
基本上,代码迭代隐式转换,并将找到的第一个转换保持为可以出现在开关中的类型。如果它找到另一个类型,则返回。如果只找到一种类型,则返回该类型。
同样,这是代码的一个简短版本,完整的代码处理更多的案例和barkwards兼容性。我添加了Roslyn的相关代码。这不是强制性的,因为规范是国王,但我想看看我是否能找到它。天真地,我期望在某个地方有Types.Count==1
<代码>:P