【问题标题】:How to use IEnumerable.Cast<> and .ToArray() to convert int array to an enum array? [duplicate]如何使用 IEnumerable.Cast<> 和 .ToArray() 将 int 数组转换为枚举数组? [复制]
【发布时间】:2016-12-15 16:27:45
【问题描述】:

考虑以下枚举声明和 int 数组:

enum Test { None };

int[] data = {0};

要将这个int[] 数组转换为Test[] 数组,我们可以简单地这样做:

Test[] result = Array.ConvertAll(data, element => (Test)element);

我最初尝试这样做:

Test[] result = data.Cast<Test>().ToArray();

但是,这会在运行时引发异常:

System.ArrayTypeMismatchException:源数组类型无法分配给目标数组类型。

问题一

有没有办法使用 Linq 和 Cast&lt;&gt; 做到这一点而不会出错,或者我必须只使用 Array.Convert()

问题二(第一个问题回答正确后添加)

究竟为什么它不起作用?

这似乎是一个实现细节转义的情况......考虑一下:

这会导致错误:

var result = data.Cast<Test>().ToList(); // Happens with "ToList()" too.

但这不是:

var result = new List<Test>();

foreach (var item in data.Cast<Test>())
    result.Add(item);

这也不是:

var result = data.Select(x => x).Cast<Test>().ToList();

明显的暗示是在导致此异常的.ToList() 实现中正在进行某种优化。


附录:

这也有效:

List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToList();

List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToArray();

只有原始数据是数组才行不通。

【问题讨论】:

  • 为什么? Array.ConvertAll 工作效率更高
  • @TimSchmelter 我想这确实是一个学术问题。
  • 现在我对它为什么不起作用很感兴趣...... :)
  • 其实Cast&lt;T&gt;和我的答案大致相同:referencesource.microsoft.com/#System.Core/System/Linq/…
  • @DanielA.White 除了你的作品和 Cast 没有!

标签: c# .net linq ienumerable


【解决方案1】:

您可以使用.Select(e =&gt; (Test)e)

【讨论】:

    【解决方案2】:

    在这种情况下它不起作用,因为Cast首先执行以下检查:

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
    {
      IEnumerable<TResult> results = source as IEnumerable<TResult>;
      if (results != null)
        return results;
      // ... the rest of the method
    }
    

    事实证明,对于 int[],此检查成功(因此 int[] as IEnumerable&lt;Test&gt; 不为空)。结果,Cast 实际上什么也没做,它按原样返回数组。然后当您调用ToArray 时,会调用Array.Copy。它尝试从int[] 数组复制到Test[] 数组,但由于类型不匹配而失败。您会看到这个异常。

    【讨论】:

    • 所以这对我来说实际上看起来像是实现中的一个错误。
    • @MatthewWatson 不是真的,原因在这里描述例如:stackoverflow.com/a/593799/5311735。简而言之,C# 和 CLR 在转换不同数字类型的数组方面有一些不同的方法。这是同样的故事,因为枚举基本上只是一个数字。您不能将 int[] 转换为 IEnumerable (或 Test[]) - 编译器不允许您这样做,因为它认为没有这样的转换。但是 CLR 允许这样做,并且在运行时这实际上会发生。
    【解决方案3】:

    因为演员实际上没有做任何事情,因为它认为集合已经是期望的类型

        IEnumerable<Test> cast = data.Cast<Test>();
        IEnumerable<Test> select = data.Select(e => (Test) e);
    
        Console.WriteLine(cast == (IEnumerable<int>) data); //True
        Console.WriteLine(select == (IEnumerable<int>) data); //False
        Console.WriteLine(select == cast); //Flase
    

    如您所见,演员 IEnumerable 实际上只是原始数组。因此.ToArray 正在尝试做类似于(Test[]) data.ToArray(); 的事情

    【讨论】:

    • 这将是实现中的错误,不是吗?
    • @MatthewWatson 从我的角度来看,是的
    • @matthew:取决于,Cast 方法不是 cast 运算符。它更严格。所以不要以这种方式使用它。您正在尝试将 int[] 转换为 Test[]。那是一种转换。 Array 类中已经有一个有意义且有效的转换方法,它可以工作
    • @TimSchmelter 这并不重要,因为如果源是 List&lt;&gt;,它就可以正常工作 - 只有当源是数组时它才会失败。 (事实证明,这是 .Net 中的一个小错误)
    猜你喜欢
    • 1970-01-01
    • 2013-01-17
    • 2021-03-10
    • 2013-08-03
    • 2018-09-12
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-04
    相关资源
    最近更新 更多