无法将类型为“System.Int32”的对象强制转换为类型“System.Int64”。

5
如果错误是“无法将类型为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”执行通用转换。它要求对象是完全相同的类型。它不能利用隐式转换等。我会发布一个答案,但我正在寻找我知道存在的重复内容。 - pinkfloydx33
1
并不是完全的重复。但它应该能够解释清楚。 - pinkfloydx33
@pinkfloydx33 相关联了,而不是被替代。谢谢。 - Soner from The Ottoman Empire
1
我不同意“dup”标志。这个涉及到2种系统类型,通常不需要任何自定义代码来转换。另一个与自定义转换运算符有关。这就是为什么这个回答了我的问题,而另一个没有的原因。 - David
@pinkfloydx33,即使多年过去了,你还在寻找吗? - Soner from The Ottoman Empire
1个回答

7

Cast(强制类型转换)和Convert(类型转换)是不同的。将 Int32 转换为 Int64 是一种语义无损转换。许多C#类型会重载 '(type)' 强制类型转换操作符并使用自定义转换运算符执行类型转换,此时不能使用类型转换。

C#语言会为常见且安全的代码模式生成隐式转换

int num = 2147483647;
long bigNum = num;

但这些是例外,规则是类型转换需要将对象分配给目标类型的变量。另一个例外是,object 类型的表达式可以强制转换为任何类型,并且如果该对象无法赋值给该类型的变量,则在运行时失败。

Enumerable.Cast<T> 会对集合中的每个元素执行 Cast 操作。这不是一种转换,即使类型实现了用户定义的转换运算符也是如此。这是因为强制转换是从 objectT,从而绕过任何用户定义的转换运算符或 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,而不是 Enumerable<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#不允许此操作,仅允许使用那些可以从约束条件推导出来的语言构造。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接