使用 c# switch 表达式时的奇怪(?)行为
Weird(?) behavior while using c# switch expression
我在使用 c# 的 switch 表达式时注意到了这一点;我想知道这是设计使然,还是其他原因。
public interface IBase
{
}
public struct Base1: IBase
{
//fields, methods, etc
}
public struct Base2: IBase
{
//fields, methods, etc
}
public struct BaseContainer: IBase
{
public IBase InnerBase{get;}
public BaseContainer(IBase value)
{
//validation and other goodies...
InnerBase = value;
}
public static implicit operator BaseContainer(Base1 value) => new BaseContainer(value);
public static implicit operator BaseContainer(Base2 value) => new BaseContainer(value);
}
public class Util
{
public static IBase NewBase(int somethingToSwitchOn)
{
return somethingToSwitchOn switch
{
1 => new Base1(),
2 => new Base2(),
_ => default(BaseContainer)
};
}
}
这是奇怪的地方:
public static void Main(string[] args)
{
var @base = Util.NewBase(1);
Console.WriteLine(@base.GetType().Name);
}
上面的代码输出“BaseContainer”,而不是预期的“Base1”,直到 ANY 的切换步骤被显式转换为 IBase
,例如:
1 => new Base1(),
2 => (IBase) new Base2(),
_ => default(BaseContainer)
这一切都与类型推断有关。存在从 Base1
和 Base2
到 BaseContainer
的隐式转换这一事实意味着在可能的装箱转换到接口之前将首先考虑它。
我们可以看到语言规范在谈论这个
Finding the best common type of a set of expressions
..snip..
More precisely, the inference starts out with an unfixed type variable X
. Output type inferences are then made from each Ei
to X
. Finally, X
is fixed and, if successful, the resulting type S
is the resulting best common type for the expressions. If no such S
exists, the expressions have no best common type.
什么是修复?
An unfixed type variable Xi
with a set of bounds is fixed as follows:
- The set of candidate types
Uj
starts out as the set of all types in the set of bounds for Xi
.
- We then examine each bound for
Xi
in turn: ..snip.. For each lower bound U
of Xi
all types Uj
to which there is not an implicit conversion from U
are removed from the candidate set. For each upper bound U
of Xi
all types Uj
from which there is not an implicit conversion to U
are removed from the candidate set.
- If among the remaining candidate types
Uj
there is a unique type V from which there is an implicit conversion to all the other candidate types, then Xi is fixed to V.
编译器需要找出 switch 表达式的类型。毕竟它的类型不能同时是Base1
, Base2
和 BaseContainer
.
为此,它 finds the best common type of the expressions 在每个 switch 表达式的分支中。根据规范,该类型与调用泛型方法时推断的类型相同:
Tr M<X>(X x1 ... X xm)
将 switch 表达式的手臂表达式作为参数传递。
我不会深入讨论类型推断的细节,但总的来说它非常直观(就像这里一样)。 new Base1()
、new Base2()
和 default(BaseContainer)
的最佳常见类型是 BaseContainer
,而 new Base1()
、(IBase)new Base2()
和 default(BaseContainer)
是 IBase
.
所以如果你不转换,那么switch表达式会产生一个BaseContainer
,这意味着你创建的新Base1
对象必须先转换为一个BaseContainer
.这将调用您的隐式运算符,其中 returns 是一个 BaseContainer
对象,因此 GetType
returns BaseContainer
.
如果您将任何一个手臂转换为 IBase
,那么整个 switch 表达式将生成 IBase
。从 Base1
到 IBase
的转换是 boxing conversion,因此不会更改其动态类型(即什么 GetType
returns)。
我在使用 c# 的 switch 表达式时注意到了这一点;我想知道这是设计使然,还是其他原因。
public interface IBase
{
}
public struct Base1: IBase
{
//fields, methods, etc
}
public struct Base2: IBase
{
//fields, methods, etc
}
public struct BaseContainer: IBase
{
public IBase InnerBase{get;}
public BaseContainer(IBase value)
{
//validation and other goodies...
InnerBase = value;
}
public static implicit operator BaseContainer(Base1 value) => new BaseContainer(value);
public static implicit operator BaseContainer(Base2 value) => new BaseContainer(value);
}
public class Util
{
public static IBase NewBase(int somethingToSwitchOn)
{
return somethingToSwitchOn switch
{
1 => new Base1(),
2 => new Base2(),
_ => default(BaseContainer)
};
}
}
这是奇怪的地方:
public static void Main(string[] args)
{
var @base = Util.NewBase(1);
Console.WriteLine(@base.GetType().Name);
}
上面的代码输出“BaseContainer”,而不是预期的“Base1”,直到 ANY 的切换步骤被显式转换为 IBase
,例如:
1 => new Base1(),
2 => (IBase) new Base2(),
_ => default(BaseContainer)
这一切都与类型推断有关。存在从 Base1
和 Base2
到 BaseContainer
的隐式转换这一事实意味着在可能的装箱转换到接口之前将首先考虑它。
我们可以看到语言规范在谈论这个
Finding the best common type of a set of expressions
..snip.. More precisely, the inference starts out with an unfixed type variable
X
. Output type inferences are then made from eachEi
toX
. Finally,X
is fixed and, if successful, the resulting typeS
is the resulting best common type for the expressions. If no suchS
exists, the expressions have no best common type.
什么是修复?
An unfixed type variable
Xi
with a set of bounds is fixed as follows:
- The set of candidate types
Uj
starts out as the set of all types in the set of bounds forXi
.- We then examine each bound for
Xi
in turn: ..snip.. For each lower boundU
ofXi
all typesUj
to which there is not an implicit conversion fromU
are removed from the candidate set. For each upper boundU
ofXi
all typesUj
from which there is not an implicit conversion toU
are removed from the candidate set.- If among the remaining candidate types
Uj
there is a unique type V from which there is an implicit conversion to all the other candidate types, then Xi is fixed to V.
编译器需要找出 switch 表达式的类型。毕竟它的类型不能同时是Base1
, Base2
和 BaseContainer
.
为此,它 finds the best common type of the expressions 在每个 switch 表达式的分支中。根据规范,该类型与调用泛型方法时推断的类型相同:
Tr M<X>(X x1 ... X xm)
将 switch 表达式的手臂表达式作为参数传递。
我不会深入讨论类型推断的细节,但总的来说它非常直观(就像这里一样)。 new Base1()
、new Base2()
和 default(BaseContainer)
的最佳常见类型是 BaseContainer
,而 new Base1()
、(IBase)new Base2()
和 default(BaseContainer)
是 IBase
.
所以如果你不转换,那么switch表达式会产生一个BaseContainer
,这意味着你创建的新Base1
对象必须先转换为一个BaseContainer
.这将调用您的隐式运算符,其中 returns 是一个 BaseContainer
对象,因此 GetType
returns BaseContainer
.
如果您将任何一个手臂转换为 IBase
,那么整个 switch 表达式将生成 IBase
。从 Base1
到 IBase
的转换是 boxing conversion,因此不会更改其动态类型(即什么 GetType
returns)。