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

时间:2016-11-20 12:49:27

标签: c# collections casting covariance

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

我现在有一组MyObj类的列表:

IEnumerable<List<MyObj>> myObjGroups

我希望将其转换/转换为

IEnumerable<List<IMyInterface>> myInterfaceGroups

我尝试的所有内容都抛出异常。

类型&#39; System.InvalidCastException&#39;发生在System.Core.dll中但未在用户代码中处理 附加信息:无法转换类型&System; Series.Collections.Generic.List`1 [MyObj]&#39;输入&#39; System.Collections.Generic.List`1 [IMyInterface]&#39;。

我试过了:

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

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

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

关于我做错了什么建议?

2 个答案:

答案 0 :(得分:2)

尝试以下方式:

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>

答案 1 :(得分:0)

你做错了什么。您无法将IEnumerable投射到List。列表是一个实际的metrialized数据集合,而运行时IEnumerable需要迭代才能检索数据。

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

检查工作小提琴: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());
    }
}