【问题标题】:Unable to cast object of type 'System.Int32' to type 'System.Int64' [duplicate]无法将“System.Int32”类型的对象转换为“System.Int64”类型[重复]
【发布时间】:2020-04-24 21:07:00
【问题描述】:

如果错误是无法将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 相反,它是相关的。谢谢
  • 我不同意“dup”标志。这一个处理 2 种系统类型,通常不需要在它们之间转换任何自定义代码。另一个与自定义转换运算符有关。这就是为什么这个回答了我的问题,而另一个没有回答。

标签: c# casting type-conversion


【解决方案1】:

Cast 与 Convert 不同。 Int32->Int64 是语义无损转换。许多 C# 类型使用 User-Definied Conversion Operator 重载 '(type)' 强制转换运算符,并在不允许类型强制转换的情况下实际执行转换。

C# 语言会为您生成一个Implicit Conversion,用于常见且安全的代码模式,例如:

int num = 2147483647;
long bigNum = num;

但是这些是类型转换要求对象可分配给目标类型的变量的规则的例外。另一个例外是 object 类型的表达式可以转换为任何类型,如果对象不能分配给该类型的变量,则会在运行时失败。

Enumerable.Cast&lt;T&gt; 完全按照它所说的去做,并对集合中的每个元素执行 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;
    }

Reference Source

注意Cast&lt;T&gt; 的参数是Enumerable,而不是Enumberable&lt;TSource&gt;。此 API 的目的是为非泛型集合提供适配器。在 .NET 中引入泛型之前(请注意,它们不仅仅是一种语言功能),Enumerable 是基本集合类型,要在 LINQ 中使用旧集合,必须将它们转换为 IEnumerable&lt;T&gt;

即使此 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# 不允许这样做; 唯一允许的语言结构是那些可以推断的 来自约束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2013-07-10
    • 2020-08-07
    • 1970-01-01
    相关资源
    最近更新 更多