bugfix> c# > 投稿

私はw笑された Range を入れようとしています(値を持つセルを含む)新しい Range の行内 。しかし、 Range から特定の要素にアクセスしようとすると 、例外がスローされます。

私はすべてを試しましたが、ここで間違っていることを誰かが知っていますか?

例外

Message: Test method xxx.MockUtilsTest.MockRowsTest threw exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot apply indexing with [] to an expression of type 'Castle.Proxies.RangeProxy'

テスト

[TestMethod]
public void MockRowsTest()
{
    var row1 = MockUtils.MockCells("test_row_1", "test_row_1");
    var row2 = MockUtils.MockCells("test_row_2", "test_row_2");
    var range = MockUtils.MockRows(row1, row2);
    Assert.IsNotNull(range);
    Assert.AreEqual(2, range.Count);
    Assert.IsNotNull(range.Rows);
    Assert.AreEqual(2, range.Rows.Count);
    Assert.AreSame(row1, range.Rows[1].Cells[1]); // exception is thrown here
    Assert.AreSame(row2, range.Rows[2].Cells[1]);
    Assert.AreEqual("test_row_1", range.Rows[1].Cells[1].Value2);
    Assert.AreEqual("test_row_2", range.Rows[2].Cells[1].Value2);
}

MockUtils

public static Range MockCellValue2(Object value)
{
    var cell = new Moq.Mock<Range>();
    cell.Setup(c => c.Value2).Returns(value);
    return cell.Object;
}
public static Range MockCells(params Object[] values)
{
    var cells = new Moq.Mock<Range>();
    for (int i = 0; i < values.Length; i++)
    {
        var cell = MockCellValue2(values[i]);
        cells.SetupGet(c => c[i + 1, Moq.It.IsAny<Object>()]).Returns(cell);
    }
    var row = new Moq.Mock<Range>();
    row.SetupGet(r => r.Cells).Returns(cells.Object);
    row.SetupGet(r => r.Count).Returns(values.Length);
    return row.Object;
}
public static Range MockRows(params Range[] rows)
{
    var mergedRows = MergeRanges(rows);
    var range = new Moq.Mock<Range>();
    range.SetupGet(r => r.Count).Returns(rows.Length);
    range.SetupGet(r => r.Rows).Returns(() => mergedRows);
    range.Setup(r => r.GetEnumerator()).Returns(rows.GetEnumerator());
    return range.Object;
}
public static Range MergeRanges(params Range[] ranges)
{
    var range = new Moq.Mock<Range>();
    for (int i = 0; i < ranges.Length; i++)
    {
        range.SetupGet(r => r[i + 1, Moq.It.IsAny<Object>()]).Returns(ranges[i]);
    }
    range.SetupGet(r => r.Count).Returns(ranges.Length);
    range.Setup(r => r.GetEnumerator()).Returns(ranges.GetEnumerator());
    return range.Object;
}

回答 1 件
  • Range のインデクサー  動的オブジェクトを返します。これが問題の原因です。

    Moqは Castle Dynamic proxy を使用します  偽のオブジェクト Castle.Proxies.RangeProxy を生成するには  あなたのケースで生成されたクラスです。このオブジェクトは COM ではないため  C#ランタイムバインダーが呼び出されるオブジェクトの処理。ランタイムバインダーは型を解決し、インデクサーメソッドを探しますが、生成されたクラスにないため、解決に失敗しました。

    あなたを解決する最も簡単な方法は、インデクサーの結果を厳密な Range に返すことです  ローカル変数:

    その後、テストは range.Rows[1] で失敗します   row1 と等しい ...

    したがって、テストコードを次のように変更します。

    [TestMethod]
    public void MockRowsTest()
    {
        var row1 = MockUtils.MockCells("test_row_1", "test_row_1");
        var row2 = MockUtils.MockCells("test_row_2", "test_row_2");
        var range = MockUtils.MockRows(row1, row2);
        Assert.IsNotNull(range);
        Assert.AreEqual(2, range.Count);
        Assert.IsNotNull(range.Rows);
        Assert.AreEqual(2, range.Rows.Count);
        Range x = range.Rows[1];
        Range y = range.Rows[2];
        var xCell = x.Cells[1];
        var yCell = y.Cells[1];
        Assert.AreSame(row1, x); 
        Assert.AreSame(row2, y);
        Assert.AreEqual("test_row_1", xCell.Value2);
        Assert.AreEqual("test_row_2", yCell.Value2);
    }
    
    

    上記のUTはテストに合格します。 IMOは、テストに合格するためではなく、コードをデバッグフレンドリーなコードにするため、「アトミックOPS(複数行)およびメソッド」への集約呼び出しを中断する必要があります(コードをデバッグするための「11THルール」と呼びます)書かれた時から少なくとも10回は読まれます...したがって、コンパイラに推移的なローカル変数を削除させて、デバッグフレンドリーなコードにします。

    ここでは、c#での動的な動作に関するリンクを含む簡単で短い説明を読むことができます。

    ここでは、Castle Dynamic Proxyについて詳しく読むことができます。

    ところで;次のこともできます。

    Range x = range.Rows[1].Cells;
    var str = x[1].Value2;
    
    

    値を受け取るために

あなたの答え