首页 > 解决方案 > 从 IEnumerable 到 List 的无效转换

问题描述

我正在 Unity3D 项目中处理 C# 脚本,我正在尝试获取字符串列表并获取排列的 2D 列表。使用此答案的 GetPermutations()方式如下:

List<string> ingredientList = new List<string>(new string[] { "ingredient1", "ingredient2", "ingredient3" });

List<List<string>> permutationLists = GetPermutations(ingredientList, ingredientList.Count);

但它会引发隐式转换错误:

IEnumerable<IEnumerable<string>> to List<List<string>> ... An explicit conversion exists (are you missing a cast)?

于是看了几个地方,比如这里,想出了如下修改:

List<List<string>> permutationLists = GetPermutations(ingredientList, ingredientList.Count).Cast<List<string>>().ToList();

但它会在运行时中断,在内部进行处理,并允许它继续运行而不指示失败——可能是因为它在 Unity3D 中运行。这是我停止调试脚本后在 Unity3D 中看到的内容:

InvalidCastException: Cannot cast from source type to destination type.
System.Linq.Enumerable+<CreateCastIterator>c__Iterator0`1[System.Collections.Generic.List`1[System.String]].MoveNext ()
System.Collections.Generic.List`1[System.Collections.Generic.List`1[System.String]].AddEnumerable (IEnumerable`1 enumerable) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:128)
System.Collections.Generic.List`1[System.Collections.Generic.List`1[System.String]]..ctor (IEnumerable`1 collection) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:65)
System.Linq.Enumerable.ToList[List`1] (IEnumerable`1 source)

我将其解释为仍然不正确地投射,因此我还尝试了以下方法以及更多我不记得的方法:

List<List<string>> permutationLists = GetPermutations(ingredientList, ingredientList.Count).Cast<List<List<string>>>();

List<List<string>> permutationLists = GetPermutations(ingredientList.AsEnumerable(), ingredientList.Count);

以及像在 C 或 Java 中那样在方法调用之前用括号显式转换,仍然无济于事。


那么我应该如何从GetPermutations()函数中转换结果来获得 a List<List<string>>?或者,我如何修改函数以仅返回List<List<string>>,因为我不需要它为泛型类型工作?我试图自己修改方法如下:

List<List<string>> GetPermutations(List<string> items, int count)
{
    int i = 0;
    foreach(var item in items)
    {
        if(count == 1)
            yield return new string[] { item };
        else
        {
            foreach(var result in GetPermutations(items.Skip(i + 1), count - 1))
                yield return new string[] { item }.Concat(result);
        }

        ++i;
    }
}

但是,<T>从函数名中删除了 ,它会中断说明主体不能是迭代器块。我以前没有使用 C# 的经验,而且我对强类型语言中的模板函数很生疏,因此感谢任何解释/帮助。

我不知道如何查找这个问题,所以如果这是重复的,只需在此处发布,我将立即删除此帖子。

标签: c#castingtype-conversion

解决方案


那么我应该如何将 GetPermutations() 函数的结果转换为List<List<string>>

最佳解决方案:不要。为什么首先需要将序列变成列表?将其保留为序列序列。

如果你必须:

GetPermutations(...).Select(s => s.ToList()).ToList()

如果你想修改原来的方法,只需做同样的事情:

IEnumerable<List<string>> GetPermutations(List<string> items, int count)
{
    int i = 0;
    foreach(var item in items)
    {
        if(count == 1)
            yield return new List<T>() { item };
        else
        {
            foreach(var result in GetPermutations(items.Skip(i + 1), count - 1))
                yield return (new string[] {item}.Concat(result)).ToList();
        }

        ++i;
    }
}

然后做GetPermutations(whatever).ToList(),你有一个列表列表。但同样,不要这样做。如果可能,请按顺序排列所有内容。

我想把这个序列变成一个列表,这样我就可以按字母顺序对元素进行排序,然后将它们重新连接为一个排序的、单个逗号分隔的字符串。

好的,那就这样做吧。让我们将您的方法重写为扩展方法Permute()。让我们做一些新的单行方法:

static public string CommaSeparate(this IEnumerable<string> items) =>
  string.Join(",", items);

static public string WithNewLines(this IEnumerable<string> items) =>
  string.Join("\n", items);

static public IEnumerable<string> StringSort(this IEnumerable<string> items) =>
  items.OrderBy(s => s);

然后我们有以下内容——我将在我们进行时对类型进行注释:

string result = 
  ingredients                    // List<string>
  .Permute()                     // IEnumerable<IEnumerable<string>>
  .Select(p => p.StringSort())   // IEnumerable<IEnumerable<string>>
  .Select(p => p.CommaSeparate())// IEnumerable<string>
  .WithNewLines();                   // string

我们完成了。 看看当您创建的方法只做一件事并且做得很好时,代码是多么清晰和直接。看看当你把所有东西都按顺序排列时是多么容易,因为它应该是。


推荐阅读