我在c#
中有以下代码段List<int> list = new List<int>() { 1, 23, 5, 3, 423, 3 };
var query = list.Cast<double>().Select(d => d);
try
{
foreach (var item in query)
{
Console.WriteLine(item);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
它编译得很完美,但是当我执行它时,我会遇到异常。
答案 0 :(得分:10)
因为你是从int到double进行类型转换,所以它不是转换它是一个类型转换,这与在一般情况下将int转换为double时有所不同。
Cast<T>
扩展方法使用IL指令unbox.any
虽然像这样的C#演员
var x = (double)42;
实际上是IL指令的结果
conv.r8
从根本上将类型拆箱为不同的类型是错误的,这就是你获得例外的原因。
答案 1 :(得分:6)
list
包含ints
,您尝试将其转换为double
。将您的查询更改为
var query = list.Select(d => (double)d);
<强>更新强>
以下是Enumerable.Cast
(.NET 4)的来源:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
if (typedSource != null) return typedSource;
if (source == null) throw Error.ArgumentNull("source");
return CastIterator<TResult>(source);
}
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
foreach (object obj in source) yield return (TResult)obj;
}
正如您所看到的,CastIterator
尝试将object
(在这种情况下为int
}加注成double
。如果目标类型与装箱的原始类型完全相同,则取消装箱操作仅会成功,因此会引发异常。 John Leidegren提供的This link详细解释了。
答案 2 :(得分:2)
.NET Framework类型转换和C#类型转换之间存在差异。他们不一样。 “将”转换为“int”是C#语言的一个特性,仅仅是语言的一个特征。
为此,C#编译器可以使用特殊指令将int转换为double。编译器在编译时知道源类型是“int”,目标类型是“double”,因此可以生成正确的指令。这实际上不是.NET Framework意义上的类型转换。
System.Int32无法类型转换为System.Double。编译Cast扩展方法时不知道源和目标集合的确切类型,因此没有生成处理 C#特定功能的特殊指令。为Cast扩展方法生成的唯一代码是普通的.NET类型转换(将类转换为其基类型,转换为对象,并将类型转换为它们实现的接口)。