2012-12-11 63 views
1

我有接受类型的参数IEnumerable(Of IEnumerable(Of MyType))铸造清单的IEnumerable((的的MyType)列出的)(IEnumerable的(的的MyType)的)

如果我以下的方法:

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

MyMethod({ list1, list2 }) 
它的工作原理是

如果我通过一个List(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。

这似乎是我所听见的.NET 4

解决任何想法,以避免这个错误类似于Casting List<MyObject> to IEnumerable<MyInterface>的问题吗?

回答

2

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

一些选项: 你可以升级到4(明显)。

您可以更改MyMethod上的签名,始终预期为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 
+0

感谢您的答复。顺便说一句,我真的不明白为什么{list1,list2}被接受。你能解释我这种行为吗? – Teejay

+0

另外,你能解释我'收益率'吗?已经看到它,但不知道如何以及为什么使用它。 – Teejay

+0

我用更多的解释和例子更新了我的答案。 – Jamey