我正在尝试将一个模拟的Range
(它包含带值的单元格)放入一个新Range
的行内。但是,当我试图从Range
访问特定元素时,抛出了一个异常。
我什么都试过了,有人知道我哪里做错了吗?
异常
消息:测试方法xxx.MockUtilsTest.MockRowsTest引发异常: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:无法将带[]的索引应用于'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;
}
发布于 2018-06-02 06:04:11
Range
的索引器返回一个动态对象,这就是问题的根源。
Castle.Proxies.RangeProxy
使用Castle Dynamic proxy
生成伪对象,在您的例子中,Moq是生成的类。由于此对象不是COM
对象,因此将调用C#运行时绑定器来处理这些对象。运行时绑定器解析类型并查找indexer方法,但他无法解析它,因为生成的类没有它。
解决这个问题的最简单方法是将索引器结果返回给一个严格的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将通过测试。我认为你应该打破对“原子OPS(多行)和方法”的聚合调用,不是因为它会通过测试,而是因为它会让你的代码成为调试友好的代码。(我称之为“第11条规则”,你的代码从编写之时起将至少被阅读10次……因此,让编译器删除可传递的局部变量,并使其成为调试友好的代码。
Here you can read a simple and short explanation with links on how dynamic works in c#.
Here you can read more about Castle Dynamic Proxy.
顺便说一句;你也可以这样做:
Range x = range.Rows[1].Cells;
var str = x[1].Value2;
来接收该值
https://stackoverflow.com/questions/50524000
复制相似问题