将List<List<object>>转换为IList<IList<object>>。

46
我已经编写了一个方法 public List<List<object>> Fetch(string data),其中我创建了一个 List<List<object>> p = new List<List<object>>(); 现在我的老板想要返回一个 IList<IList<object>> 而不是 List<List<object>>, 也就是说: public IList<IList<object>> Fetch(string data) 当我尝试这样做时: return (IList<IList<object>>) p; // 抛出异常 如何将 List<List<object>> 转换为 IList<IList<object>> 并再次转换为 List<List<object>>

2
如果您需要将其转换回去,则您的设计很可能已经出错了。 - Albin Sunnanbo
6个回答

94

你不能通过直接强制转换来执行该转换-这样做是不安全的。相反,你应该使用:

IList<IList<object>> ret = new List<IList<object>>();

然后对于每个“子列表”,您可以使用:

// Or whatever
ret.Add(new List<object>());

最后,只需返回ret

当你返回时,你可以使用LINQ来执行现有的List<List<object>>的转换 - 但最好还是创建一个更合适的类型,如上所示。


为了理解为什么一些现有的答案是错误的,假设你可以这样做:

IList<IList<object>> p = new List<List<object>>();

那么这个是合法的:

List<List<object>> listOfLists = new List<List<object>>();
IList<IList<object>> p = listOfLists;
p.Add(new object[]);
List<object> list = p[0];

但是p[0]是一个指向object[]的引用,而不是一个List<object>...我们原本认为类型安全的代码看起来不那么安全了...

幸运的是,IList<T>是协变的,可以防止这个问题。


4
@JonSkeet 哦,我不知道数组也实现了IList。 - Muhammad Hasan Khan
@JonSkeet 如果 tabOfTabdouble[][],那么 IList<IList<double>> listOfList = tabOfTab; 怎么样? - Adrien Piquerez
@DineMartin:关于什么?我不确定你在寻找什么。 - Jon Skeet
@DineMartin:这可能是由于数组的差异,例如如何将string[]视为object[] - Jon Skeet
@JonSkeet 但我无法将 double[] 转换为类型 object[]。 - Adrien Piquerez
显示剩余6条评论

14
你需要将你的列表声明为:
IList<IList<object>> list = new List<IList<object>>(); // Works!

这个方法可行,因为一开始只创建了外部列表。然后,您可以插入与 IList<object> 兼容的单个项目:

list.Add(new List<object>());
list.Add(new object[10]);

4
var myOriginalList = new List<List<Object>>();
var converted = ((IList<IList<Object>>)myOriginalList.Cast<IList<Object>>().ToList()); // EDIT: Added .ToList() here

您不需要进行转换 - 您可以在 IList 上执行几乎与 List 相同的任何操作。


2
为什么要费心创建一个新列表呢?直接创建正确的类型会更简单。 - Jon Skeet
完全同意,你的方法讲解得非常清楚。我将其保留以展示如果需要这样做(例如第三方库返回了一个List<List<Object>>,而你需要将其转换为另一个第三方库),可以采用这种方式实现。 - Chris Shain

2

您需要将结果变量的声明从List<List<object>>更改为IList<IList<object>>

您可以使用List<IList<object>>进行实例化

结果中的每个项目都可以是List<object>类型

    static IList<IList<object>> Test()
    {
        IList<IList<object>> result = new List<IList<object>>();
        var item = new List<object>() { "one", "two", "three" };
        result.Add(item);
        return result;
    }

1
public IList<IList<object>> Fetch(string data)
{
  IList<IList<object>> p = new List<IList<object>>();

  // add your stuff here

  return p;
}

@vidstige JonSkeet大约正确了30秒。我最初有IList<IList<object>> p = newList<List<object>>();这将无法编译,也不应该。我发帖后10秒钟就注意到了我的错误。十秒钟。进一步证明JonSkeet实际上是一个机器人。=)我不知道那天与Hanselman交谈的是谁... - John Ruiz
笑,很快没错。但是我看不到你的帖子被编辑了?也许有一些“静默时间”可以在没有新版本的情况下进行编辑…… - vidstige

0

List<T>IList<T>不支持协变。因此,以下代码无法编译:

List<List<string>> list = new List<IList<string>>(); // DOES NOT COMPILE!!!!!

List<T> 已经是类型为 IList<T>,不需要协变或逆变。 - AllenG
1
@AllenG,你能解释一下为什么我放置的那段代码片段无法编译吗? - Aliostad
2
@AllenG:是的,这里确实需要逆变性,因为List<List<string>>不是List<IList<string>>。你试过编译Aliostad说不能编译的代码吗?它真的不能编译。 - Jon Skeet
我在你添加代码片段之前已经添加了我的评论。List<List<T>> 应该是具有签名 IList<IList<T>> 的方法的有效返回。 - AllenG
@AllenG,这仍然不能证明downvote的合理性。 OP遇到的问题是由于ILst和List中缺乏协变/逆变性导致的。 - Aliostad
5
@AllenG: 不,绝对不应该这样做。这里有太多的列表。对于一个被类型定义为返回IList<Box>的方法,List<Box>是否应该是有效的返回值? 是的。但是,对于一个被类型定义为返回IList<IContainer>的方法,List<Box>是否应该是有效的返回值?不,绝对不应该。调用者合理地期望他们可以将一个Bottle插入到IList<IContainer>中,但你手头拥有的是一个无法包含Bottle的List<Box>。因此,这种转换必须是非法的。 - Eric Lippert

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