看来 List 对象不能存储在 C# 中的 List 变量中,甚至不能以这种方式显式转换。

List<string> sl = new List<string>();
List<object> ol;
ol = sl;

结果无法隐式转换类型 System.Collections.Generic.List<string>System.Collections.Generic.List<object>

进而...

List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;

结果无法转换类型 System.Collections.Generic.List<string>System.Collections.Generic.List<object>

当然,您可以通过将所有内容从字符串列表中取出并一次将其放回其中来完成此操作,但这是一个相当复杂的解决方案。

有帮助吗?

解决方案

可以这样想,如果您要执行这样的转换,然后将 Foo 类型的对象添加到列表中,则字符串列表将不再一致。如果您要迭代第一个引用,您将得到一个类转换异常,因为一旦您命中 Foo 实例,Foo 就无法转换为字符串!

作为旁注,我认为是否可以进行反向转换会更重要:

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

我已经有一段时间没有使用 C# 了,所以我不知道这是否合法,但这种类型转换实际上(可能)有用。在这种情况下,您将从一个更通用的类(对象)转到一个从通用类扩展的更具体的类(字符串)。这样,如果添加到字符串列表中,就不会违反对象列表。

有人知道或可以测试这样的强制转换在 C# 中是否合法吗?

其他提示

如果您使用 .NET 3.5,请查看 Enumerable.Cast 方法。它是一个扩展方法,因此您可以直接在列表上调用它。

List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();

这不完全是你所要求的,但应该可以解决问题。

编辑:正如 Zooba 所指出的,您可以调用 ol.ToList() 来获取列表

您不能在具有不同类型参数的泛型类型之间进行转换。专用泛型类型不构成同一继承树的一部分,因此是不相关的类型。

要在 NET 3.5 之前执行此操作:

List<string> sl = new List<string>();
// Add strings to sl

List<object> ol = new List<object>();

foreach(string s in sl)
{
    ol.Add((object)s);  // The cast is performed implicitly even if omitted
}

使用 Linq:

var sl = new List<string>();
// Add strings to sl

var ol = new List<object>(sl.Cast<object>());

// OR
var ol = sl.Cast<object>().ToList();

// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();

原因是像这样的泛型类 List<> 在大多数情况下,在外部将其视为普通类。例如当你说 List<string>() 编译器说 ListString() (其中包含字符串)。[技术人员:这是所发生事情的极其简单的英语版本]

因此,显然编译器不能足够聪明,无法通过强制转换其内部集合的项目来将 ListString 转换为 ListObject。

这就是为什么 IEnumerable 有像 Convert() 这样的扩展方法,可以让您轻松地为存储在集合中的项目提供转换,这就像从一个集合转换到另一个集合一样简单。

这与协变有很大关系,例如,泛型类型被视为参数,如果参数不能正确解析为更具体的类型,则操作会失败。这意味着您确实无法转换为更通用的类型(例如对象)。正如 Rex 所说,List 对象不会为您转换每个对象。

您可能想尝试使用 ff 代码:

List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);

或者:

List<object> ol = new List<object>();
ol.AddRange(sl);

ol 将(理论上)毫无问题地复制 sl 的所有内容。

是的,您可以从 .NET 3.5 开始:

List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();

Mike - 我相信 C# 中也不允许逆变

CLR 中的通用类型参数差异 了解更多信息。

这实际上是为了让您不会尝试在“ol”列表变体中放入任何奇怪的“对象”(如 List<object> 似乎允许) - 因为你的代码会崩溃(因为列表确实是 List<string> 并且只接受 String 类型对象)。这就是为什么您不能将变量转换为更通用的规范。

在 Java 上则相反,你没有泛型,而是运行时的所有对象列表,并且你确实可以将任何奇怪的对象填充到你所谓的严格类型列表中。搜索“Reified generics”以查看对 java 问题的更广泛讨论......

不支持泛型上的这种协变,但实际上可以使用数组来做到这一点:

object[] a = new string[] {"spam", "eggs"};

C# 执行运行时检查以防止您放置诸如 int 进入 a.

这是另一个 .NET 3.5 之前的解决方案,适用于任何 IList,其内容可以隐式转换。

public IList<B> ConvertIList<D, B>(IList<D> list) where D : B
{
    List<B> newList = new List<B>();

    foreach (D item in list)
    {
        newList.Add(item);
    }

    return newList;
}

(基于Zooba的例子)

我有一个:

private List<Leerling> Leerlingen = new List<Leerling>();

我打算用收集到的数据来填充它 List<object>最终对我有用的是这个:

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();

.Cast 它是你想要的类型 IEnumerable 从该类型,然后类型转换 IEnemuerableList<> 你要。

嗯,感谢之前的评论,我找到了两种方法来找到它。第一个是获取元素的字符串列表,然后将其转换为 IEnumerable 对象列表:

IEnumerable<object> ob;
List<string> st = new List<string>();
ob = st.Cast<object>();

第二个是避免 IEnumerable 对象类型,只需将字符串转换为对象类型,然后在同一句子中使用函数“toList()”:

List<string> st = new List<string>();
List<object> ob = st.Cast<object>().ToList();

我更喜欢第二种方式。我希望这有帮助。

List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top