4

2D オブジェクト配列の行を遅延ロード (yield リターンによる拡張) しようとしています。次のエラーが表示されます。

c# '<>d__6' 型のオブジェクトを 'System.Object[]' 型にキャストできません。

Parseメソッドにある次の行で例外が発生します。

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 でプログラミングしています)。

コンパイルとテストに使用できるコード (In 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);
        }

    }
4

2 に答える 2

5

コメントのすべての情報により、ここで何が起こっているかが明確になりました。もっと単純な再現を作りましょう:

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

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

OK、コンパイラはbottomメソッドで何をしますか? それを次のように書き換えます。

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 が返されます。それをオブジェクトに変換します。次に、オブジェクトを Tiger にキャストします。しかし、ForEachRowEnumerable はトラではありません。これは一連のトラを与えるクラスです。したがって、ランタイムは「ForEachRowEnumerable を Tiger にキャストできません」というエラーを返します。

もちろん、C# コンパイラはそのクラスに「ForEachRowEnumerable」という名前を付けません。そのクラスを実際に名前で<>d__6使用することが不可能であることを確認するために、名前を付けます。

于 2013-01-31T21:56:45.817 に答える