1

我有一个接受类型参数的方法IEnumerable(Of IEnumerable(Of MyType))

如果我执行以下操作:

Dim list1 as new List(Of MyType) From { obj1, obj2 }
Dim list2 as new List(Of MyType) From { obj3, obj4 }

MyMethod({ list1, list2 })

有用。

如果我通过 aList(Of List(Of MyType))它编译但给出运行时错误,如下所示:

System.InvalidCastException: Unable to cast object of type
'System.Collections.Generic.List`1[System.Collections.Generic.List`1[MyType]]' to type
'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IEnumerable`1[MyType]]'

如果我通过MyType()()它会给出编译时错误,如下所示:

Value of type '2-dimensional array of MyType' cannot be converted to
'System.Collections.Generic.IEnumerable(Of System.Collections.Generic.IEnumerable(Of MyType))'

我目前正在使用.net 3.5。

这似乎是一个类似于Casting List<MyObject> to IEnumerable<MyInterface>的问题,我听说在 .net 4 中已解决。

有什么想法可以避免这个错误吗?

4

1 回答 1

2

发生运行时错误,因为直到 .NET 4 才引入对通用接口的方差支持。 http://msdn.microsoft.com/en-us/library/dd233059.aspx

一些选项:您可以升级到 4(显然)。

您可以将签名更改MyMethod为 always expect List(Of List(Of T))

您可以编写一个扩展方法来List(Of List(Of T))IEnumerable(Of IEnumerable(Of T)). 但是,您可能希望在 C# 程序集中执行此操作,因此您可以利用yield return. 我想不出在 VB.Net 中处理它的好方法。

诀窍是将需要从 List 隐式转换为 IEnumerable 的泛型维数降至 1。3.5 框架可以处理泛型类型的 1 维的隐式转换,但不能像您的示例中那样处理 2 维。

下面的例子:

3.5 C#项目:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2Helpers
{
    public static class My35Extensions
    {   
        public static  IEnumerable<IEnumerable<T>> ToIEnumerableOfIEnumerable<T>(this List<List<T>> value)
        {
            foreach (var v1 in value)
            {
                yield return v1;
            }
        }
    }
}

3.5 VB.Net 项目基于您的原始示例:

Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.CompilerServices
Imports ConsoleApplication2Helpers.My35Extensions


Module Module1

    Sub Main()
        Dim obj1 As New MyType, obj2 As New MyType, obj3 As New MyType, obj4 As New MyType
        Dim list1 As New List(Of MyType) From {obj1, obj2}
        Dim list2 As New List(Of MyType) From {obj3, obj4}
        Dim arg1 = {list1, list2}

        ' Works in 3.5 and 4.  The non-generic array can be implicitly converted to IEnumerable.
        ' Then the framework only has one more dimension for the second IEnumerable conversion.
        ' The single dimension can convert implicitly in .NET 3.5 or 4.
        MyMethod(arg1)


        Dim arg2 As New List(Of List(Of MyType))
        arg2.Add(list1)
        arg2.Add(list2)

        ' Works in .NET 4 but NOT 3.5 because .NET Framework 4 introduces variance support for several existing generic interfaces.
        'MyMethod(arg2)

        ' Works in .NET 4 or 3.5.
        ' Uses custom extension method to implicitly convert the outer List<T> to IEnumerable<T>, so we can run in .NET 3.5.
        MyMethod(arg2.ToIEnumerableOfIEnumerable())

        Console.ReadKey()
    End Sub

    Sub MyMethod(value As IEnumerable(Of IEnumerable(Of MyType)))
        '
    End Sub

End Module


Public Class MyType
    Public Sub New()

    End Sub
End Class
于 2012-12-19T23:33:01.460 回答