如果错误是无法将类型System.Int64
的对象强制转换为类型System.Int32
,我可以理解这是由于数据缩小的可能性。然而,我不明白为什么会出现错误,无法将System.Int32
类型的对象强制转换为System.Int64
类型,尽管long
的范围更高。
int[] integers = { 1, 2, 3 };
IEnumerable<long> test1 = integers.OfType<long>();
IEnumerable<long> test2 = integers.Cast<long>();
foreach (var l in test2) ;
Cast与Convert不同。Int32
->Int64
是一种语义无损转换。许多C#类型使用用户定义的转换运算符重载"(type("转换运算符,并实际执行不允许类型转换的转换。
C#语言将为您生成一个隐式转换,用于常见和安全的代码模式,如:
int num = 2147483647;
long bigNum = num;
但这些都是例外,即类型转换要求对象可分配给目标类型的变量。另一个例外是,类型为object
的表达式可以强制转换为任何类型,并且如果对象不能分配给该类型的变量,则在运行时将失败。
Enumerable.Cast<T>
完全按照它所说的去做,并对集合中的每个元素执行Cast。即使类型实现了用户定义的转换运算符,也不是转换。这是因为强制转换是从object
到T
的,因此绕过了任何用户定义的转换运算符或C#隐式转换
来源:
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;
}
参考源
请注意,Cast<T>
的自变量是Enumerable
,而不是Enumberable<TSource>
。这个API的目的是为非泛型集合提供一个适配器。在泛型被引入.NET之前(请注意,它们不仅仅是一种语言功能(,Enumerable
是基本集合类型,要使用LINQ中的旧集合,有必要将它们转换为IEnumerable<T>
。
即使这个API的目标是应用用户定义的转换或隐式转换,C#中也没有明显的方法来实现它。C#泛型不是模板,泛型方法将有一个必须遵循C#规则的单个实现。例如这样的东西;
public static IEnumerable<TDest> MyCast<TDest, TSource>(this IEnumerable<TSource> col)
{
foreach (var s in col)
yield return (TDest)s;
}
无法编译,因为编译器无法验证TDest是否可从TSource类型的对象赋值。因此,您必须首先将每个项强制转换为object
,这正是采用非通用IEnumerable的版本中发生的情况。
你可以写一些类似的东西
yield return (TDest)Convert.ChangeType(s, typeof(TDest));
但方法应该是:
public static class MyConvertExtension
{
public static IEnumerable<TDest> Convert<TDest, TSource>(this IEnumerable<TSource> col)
{
foreach (var s in col)
yield return (TDest)Convert.ChangeType(s, typeof(TDest));
}
}
*C++模板与C#泛型的区别
C++允许的代码可能对模板,然后检查用作类型的特定类型参数C#要求类中的代码以这样的方式编写它将与满足约束的任何类型一起工作。对于例如,在C++中,可以编写一个使用类型参数的对象上的算术运算符+和-将在实例化模板时产生错误具有不支持这些运算符的类型。C#不允许这样做;唯一允许的语言构造是那些可以推导的不受约束。