在 C# 中,为什么这种从对象列表到接口列表的转换会抛出异常?

In C#, why is this conversion from list of objects to list of interfaces throwing an exception?

在 C# 中,我有一个 class MyObj 实现了一个接口 IMyInterface.

我现在有一个 MyObj 列表集合 class:

IEnumerable<List<MyObj>> myObjGroups

我想将其转换/转换为

IEnumerable<List<IMyInterface>> myInterfaceGroups

而且我尝试的所有操作都引发了异常。

'System.InvalidCastException' 类型的异常发生在 System.Core.dll 但未在用户代码中处理 附加信息:无法将类型 'System.Collections.Generic.List`1[MyObj]' 的对象转换为类型 'System.Collections.Generic.List`1[IMyInterface]'.

我试过:

IEnumerable<List<IMyInterface>> myInterfaceGroups= new List<List<IMyInterface>>(myObjGroups.Cast<List<IMyInterface>>());

和:

IEnumerable<List<IMyInterface>> myList = myObjGroups.Cast<List<IMyInterface>>();

并且两者似乎都在 运行 时间抛出异常。

对我做错了什么有什么建议吗?

按以下方式尝试:

IEnumerable<List<IMyInterface>> myInterfaceGroups = myObjGroups
    .Select(l => l.Select(o => (IMyInterface)o).ToList());

或者如果您更喜欢使用 Cast<T>() 扩展方法:

IEnumerable<List<IMyInterface>> myInterfaceGroups = myObjGroups
    .Select(l => l.Cast<IMyInterface>().ToList());

编辑:一点解释

为了更好地理解为什么会出现 InvalidCastException 异常,让我们尝试分解您的原始表达式:

IEnumerable<List<IMyInterface>> myInterfaceGroups = 
    new List<List<IMyInterface>>(myObjGroups.Cast<List<IMyInterface>>());

这相当于:

IEnumerable<List<IMyInterface>> myObjGroupsAsInterfaceList = myObjGroups
    .Cast<List<IMyInterface>>()
    .ToList();

IEnumerable<List<IMyInterface>> myInterfaceGroups = new List<List<IMyInterface>>(myObjGroupsAsInterfaceList);

Cast<T>() 扩展方法只是遍历项目并尝试将每个项目转换为类型 T。我们可以用以下代码片段替换 Cast<T>() 扩展方法与 ToList<T>() 相结合的功能:

List<List<IMyInterface>> myObjGroupsAsInterfaceList = new List<List<IMyInterface>>();
foreach (List<MyObj> myObjGroup in myObjGroups)
{
    List<IMyInterface> myObjGroupAsInterface = myObjGroup; // Compile error!
    myObjGroupsAsInterfaceList.Add(myObjGroupAsInterface);
}

所以根本问题是您不能将 List<MyObj> 对象分配给 List<IMyInterface> 类型的变量。

要找到关于为什么上述不可能的更多解释,请查看以下问题:C# variance problem: Assigning List<Derived> as List<Base>

你做错了什么。您不能将 IEnumerable 转换为 List。列表是实际的数据集合,而 运行 次 IEnumerable 需要迭代才能检索数据。

要解决您的问题,您需要转换为 IEnumerable<IMyInterface>:

检查工作 Fiddle:Here(下同)

public class Program
{
    static IEnumerable<List<MyObj>> Get()
    {
        yield return new List<MyObj>();
        yield return new List<MyObj>();
    }

    static void Main()
    {
        IEnumerable<List<MyObj>> myObjGroups = Get();

        var result = myObjGroups.Cast<IEnumerable<IMyInterface>>();

        foreach(var val in result)
            Console.WriteLine(val.Count());
    }
}