Cast 与 Convert 不同。 Int32->Int64 是语义无损转换。许多 C# 类型使用 User-Definied Conversion Operator 重载 '(type)' 强制转换运算符,并在不允许类型强制转换的情况下实际执行转换。
C# 语言会为您生成一个Implicit Conversion,用于常见且安全的代码模式,例如:
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;
}
Reference Source
注意Cast<T> 的参数是Enumerable,而不是Enumberable<TSource>。此 API 的目的是为非泛型集合提供适配器。在 .NET 中引入泛型之前(请注意,它们不仅仅是一种语言功能),Enumerable 是基本集合类型,要在 LINQ 中使用旧集合,必须将它们转换为 IEnumerable<T>。
即使此 API 的目标是应用用户定义的转换或隐式转换,在 C# 中也没有明显的方法来实现它。 C# 泛型不是模板*,泛型方法将有一个必须遵循 C# 规则的实现。 EG 是这样的;
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));
}
}
*Differences Between C++ Templates and C# Generics
C++ 允许代码可能不适用于
模板,然后检查用作类型的特定类型
范围。 C# 要求类中的代码以这种方式编写
它将适用于任何满足约束的类型。为了
例如,在 C++ 中,可以编写一个使用
算术运算符 + 和 - 在类型参数的对象上,其中
在模板实例化时会产生错误
使用不支持这些运算符的类型。 C# 不允许这样做;
唯一允许的语言结构是那些可以推断的
来自约束。