C# “为什么可以转换?”;(详)(反对)";要从类型参数编译吗?
来自C#5.0语言规范: 上述规则不允许从 非接口类型的无约束类型参数,可能是 令人惊讶的制定这条规则的原因是为了防止混淆和使 这种转换的语义很清楚。例如,考虑 以下声明:C# “为什么可以转换?”;(详)(反对)";要从类型参数编译吗?,c#,C#,来自C#5.0语言规范: 上述规则不允许从 非接口类型的无约束类型参数,可能是 令人惊讶的制定这条规则的原因是为了防止混淆和使 这种转换的语义很清楚。例如,考虑 以下声明: class X<T> { public static long F(T t) { return (long)t; // Error } } 此代码现在将编译,但执行X.F(7)将 在运行时引发异常,因为装箱的int无法转换 直接到一个长的 为什么添加(对象)会使编译工
class X<T>
{
public static long F(T t) {
return (long)t; // Error
}
}
此代码现在将编译,但执行X.F(7)
将
在运行时引发异常,因为装箱的int无法转换
直接到一个长的
为什么添加(对象)
会使编译工作正常
在第一个示例中,如果我是正确的,(long)t
中的(long)
表示没有歧义的标准数字转换,这要求t
的实际类型是一种可以通过(long)
转换为long的数字类型。由于无法保证t
的实际类型,因此编译失败
在第二个例子中
- 在
中的(long)(object)t
是否意味着取消装箱转换,而不会与其他类型的转换产生歧义(long)
中的(long)(object)t
是否要求(long)
为盒装长字符?但是不能保证(object)t
必须是一个装箱的长文本,那么为什么编译没有失败呢(object)t
谢谢。第二个问题:编译成功是因为编译器允许这种“是的,我真的,真的是认真的”特殊情况,允许您处理逻辑上知道
t
将很长的情况,但编译器无法通过编译时的静态分析以某种方式证明这一点。如果你错了,它会抛出一个异常,这是你的问题。这并不是说你永远不能把一根绳子拉得太长,太长,太长,太长;这只是个例外。编译器只是帮了你一把,所以你不会完全出于偶然。谢谢。(1) 在第一个例子中,编译器是否认为(long)t
只是标准的数字转换,或者可能是其他类型的转换,例如取消装箱?(2) 在第二个示例中,编译器是否只将(long)(object)t
中的(long)
看作是拆箱转换?编译器是否只将(long)(object)t
中的(object)
看作是装箱转换,或者可能是其他类型的转换,例如引用转换?我认为将object强制转换为long显然是拆箱;其余的,我不会冒险去猜。编译一些测试用例并转储MSIL可能是有益的;这将非常明确地告诉您编译器对转换的看法。还有一位前C#编译器团队成员,他经常光顾这里的C#标签,他对解释非常慷慨;您可能会收到他的来信。在示例1中,(long)t
表示对long
的任何有效转换,这可能包括数字转换,但也包括取消装箱转换。T
不合法,因为如果源类型未知,编译器无法验证是否存在合法转换。示例2是合法的,因为与对象
之间的转换对于T
可以想象的任何类型都是合法的。我能想到的唯一不能与object
转换的类型是指针,而t
不能是指针类型。(long)(object)
中的(object)
可以是装箱转换或引用转换。应用的实际转换将取决于泛型实例化。当专门用于值类型时,它将是装箱转换。对于引用类型,请执行引用转换。它永远不会是用户定义的转换(自定义转换运算符)。第二个问题:编译成功是因为编译器允许这种“是的,我真的,真的是这么说的”特殊情况,允许您处理逻辑上知道t
将很长的情况,但是编译器不能通过编译时的静态分析来证明这一点。如果你错了,它会抛出一个异常,这是你的问题。这并不是说你永远不能把一根绳子拉得太长,太长,太长,太长;这只是个例外。编译器只是帮了你一把,所以你不会完全出于偶然。谢谢。(1) 在第一个例子中,编译器是否认为(long)t
只是标准的数字转换,或者可能是其他类型的转换,例如取消装箱?(2) 在第二个示例中,编译器是否只将(long)(object)t
中的(long)
看作是拆箱转换?编译器是否只将(long)(object)t
中的(object)
看作是装箱转换,或者可能是其他类型的转换,例如引用转换?我认为将object强制转换为long显然是拆箱;其余的,我不会冒险去猜。编译一些测试用例并转储MSIL可能是有益的;这将非常明确地告诉您编译器对转换的看法。还有一位前C#编译器团队成员,他经常光顾这里的C#标签,他对解释非常慷慨;您可能会收到他的来信。在示例1中,(long)t
表示对long
的任何有效转换,这可能包括数字转换,但也包括取消装箱转换。T
不合法,因为如果源类型未知,编译器无法验证是否存在合法转换。示例2是合法的,因为与对象
之间的转换对于T
可以想象的任何类型都是合法的。我能想到的唯一不能与object
转换的类型是指针,而t
不能是指针类型。(long)(object)
中的(object)
可以是装箱转换或引用转换。实际情况
class X<T>
{
public static long F(T t) {
return (long)(object)t; // Ok, but will only work when T is long
}
}