2013-01-31 90 views
4

我試圖懶加載(擴展與yield return)2D對象數組中的行。我得到以下錯誤:在這條線的Parse方法發現無法投入'<> d__6'類型的對象來鍵入'System.Object []'

c# Unable to cast object of type '<>d__6' to type 'System.Object[]'.

發生異常:

yield return (TSource) conversion(o); 

我不明白爲什麼C#認爲返回值是<>d__6而不是Object[]。我通常編程在VB.NET,所以我不認爲我瞭解C#的細微差別。我究竟做錯了什麼?我看了其他類似的問題/答案,但我仍然感到困惑。

public static IEnumerable<TSource> Parse<TSource>(this object[,] array 
     , Func<IEnumerable<object[]>, IEnumerable<TSource>> conversion 
     , int rowStart, int columnStart, int rowCount, int columnCount) 
    { 

     IEnumerable<object[]> o 
      = array.ForEachRow(rowStart, columnStart, rowCount, columnCount); 

     yield return (TSource) conversion(o); 

    } 

ForEachRow方法:

public static IEnumerable<object[]> ForEachRow(this object[,] array, 
       int rowStart, int columnStart, int rowCount, int columnCount) 
    { 

     object[] array1d=new object[columnCount]; 
     for (int row = rowStart; row < rowCount; row++) 
     { 
      for (int column = columnStart; column < columnCount; column++) 
      { 
       array1d[column] = array[row, column]; 
      } 
      yield return (object[]) array1d; 
     } 
    } 

我知道這個問題已經被問過,但對方的回答沒有任何意義,我很遺憾(在VB我計劃居多)。你可以用它來編譯和測試(在VB.NET

代碼:

基本上我越來越從Excel 2D對象數組,並希望把它放在一個類,並使用LINQ到評估。

Dim oData As Object(,) = {{"OrderDate", "Region", "Rep", "Item", "Units", "Unit Cost", "Total"} _ 
     , {New DateTime(2011, 1, 6), "East", "Jones", "Pencil", 95, 1.99, 189.05} _ 
     , {New DateTime(2011, 1, 23), "Central", "Kivell", "Binder", 50, 19.99, 999.5} _ 
     , {New DateTime(2011, 2, 9), "Central", "Jardine", "Pencil", 36, 4.99, 179.64} _ 
     , {New DateTime(2011, 2, 26), "Central", "Gill", "Pen", 27, 19.99, 539.73} _ 
     , {New DateTime(2011, 3, 15), "West", "Sorvino", "Pencil", 56, 2.99, 167.44} _ 
     } 

    Dim clsSales = oData.Parse(Of SaleOrder)(Function(o As Object()) New SaleOrder(_ 
             If(IsDate(o(0)), o(0), #1/1/1900#) _ 
             , o(1).ToString _ 
             , o(2).ToString _ 
             , o(3).ToString _ 
             , If(IsNumeric(o(4)), CInt(o(4)), 0) _ 
             , If(IsNumeric(o(5)), o(5), 0) _ 
             ), 1, 0, oData.GetUpperBound(0), 6) 

    For Each cls In clsSales 
     Console.WriteLine(cls.ToString) 
    Next 

凡類:

Class SaleOrder 

Public Sub New(ByVal date_ As Date, ByVal region_ As String, ByVal rep As String, ByVal item_ As String, ByVal units As Integer _ 
       , ByVal cost As Double) 

    OrderDate = date_ 
    Region = region_ 
    Representative = rep 
    Item = item_ 
    UnitCount = units 
    UnitCost = cost 

End Sub 

Public OrderDate As DateTime 
Public Region As String 
Public Representative As String 
Public Item As String 
Public UnitCount As Integer = 5 
Public UnitCost As Double 
Public ReadOnly Property Total() As Double 
    Get 
     Return UnitCount * UnitCost 
    End Get 
End Property 

Public Overrides Function ToString() As String 
    Return String.Format("{0} {1} {2} {3} {4} {5} {6}", OrderDate, Region, Representative, Item, UnitCount, UnitCost, Total) 
End Function 

End Class 

最終解決

public static IEnumerable<TSource> Parse<TSource>(this object[,] array 
     , Func<object[], TSource> conversion 
     , int rowStart, int columnStart, int rowCount, int columnCount) 
    { 

     for (int row = rowStart; row < rowCount; row++) 
     { 
      object[] array1d = new object[columnCount]; 
      for (int column = columnStart; column < columnCount; column++) 
      { 
       array1d[column] = array[row, column]; 
      } 
      yield return conversion(array1d); 
     } 

    } 
+0

在哪一行你會得到異常? –

+0

如果你提供一個簡短的*完整的例子來證明問題,那真的很有幫助。這裏有很多事情發生,我們甚至不知道'TSource'是什麼,或者你的轉換委託人做了什麼。也很不清楚,爲什麼你將'array1d'轉換爲'object []'時,它的類型已經... –

+0

好吧,用我得到錯誤的代碼行更新並刪除了一些代碼,相關。 – Jon49

回答

4

oIEnumerable<object[]>

conversion(o)IEnumerable<TSource>。您正在將一系列對象轉換爲TSource項目的序列。

然後,您將IEnumerable<TSource>轉換爲TSource。你基本上是在說:「將TSource項目的這個順序作爲一個單獨的TSource項目處理。」什麼是運行時告訴你的是,「我不能把項目作爲TSource項目的該序列,因爲這不是它是什麼。

你幾乎肯定要實際上什麼做的只是更換到最後一行:

return conversion(o); 

你的TSource項目序列,而這正是你需要嘗試使用迭代器塊返回你是得太多就什麼

如果你真的,真的。想要使用迭代器塊,那麼你需要屈服序列中的每個項目如下所示:

foreach (TSource item in conversion(o)) 
    yield return item; 

但爲什麼要麻煩。

+0

謝謝,我會檢查你的答案,並標記正確的,如果我得到它的工作。 – Jon49

5

隨着評論中的所有信息,現在清楚發生了什麼。讓我們做一個更簡單的repro:

public static IEnumerable<Tiger> Parse() 
{ 
    object obj = ForEachRow(); 
    yield return (Tiger) obj; 
} 

public static IEnumerable<Tiger> ForEachRow() 
{ 
    yield return new Tiger(); 
} 

好的,編譯器用底部方法做什麼?它重寫爲這樣:

class ForEachRowEnumerable : IEnumerable<Tiger> 
{ 
    ... a class which implements an IEnumerable<Tiger> 
    that yields a single tiger... 
} 

public static IEnumerable<Tiger> ForEachRow() 
{ 
    return new ForEachRowEnumerable(); 
} 

那麼現在第一種方法做什麼?

您致電ForEachRow。這會返回一個新的ForEachRowEnumerable。你將它轉換爲對象。然後,您將該物體投擲到老虎身上。但是ForEachRowEnumerable不是老虎;這是一個能夠給你一連串老虎的課程。所以運行時會給你錯誤「不能將ForEachRowEnumerable強制轉換爲Tiger」。

C#編譯器當然不會將該類命名爲「ForEachRowEnumerable」。它將其命名爲<>d__6以確保您無法按名稱實際使用該類。

+0

感謝您使用簡單代碼的例子。在將來的問題中,我將確保按照您演示的方式簡化我的代碼。 – Jon49

+2

@ Jon49:不客氣。使用簡化的複製代碼不僅可以讓您在這裏獲得更好的答案,還可以避免您首先提出問題。這是另一種形式的橡皮鴨調試。請參閱http://www.codinghorror.com/blog/2012/03/rubber-duck-problem-solving.html和http://en.wikipedia.org/wiki/Rubber_duck_debugging –

相關問題