【发布时间】:2014-01-03 03:45:23
【问题描述】:
我不确定这是否是起订量问题,或者我做了一些显而易见的事情,而且我已经研究了太久了。
通过以下语句,我得到了一些非常奇怪的结果:
var orderedFiles = files
.Select(p => {
var post = _serializer.Deserialize<BlogPostModel>(_fs.File.ReadAllText(p));
post.FileDate = GetFileNameDate(p);
post.FilePath = p;
return post;
})
.OrderByDescending(x => x.FileDate);
当我枚举这个时,(通过使用 orderedFiles.ToArray() 或 .ToList())我将返回原始“文件”数组中的最后一个元素,返回可枚举中的所有元素。所以,对于下面的测试,我得到了预计的 file5 值,5 次。
当我在 Select() 方法调用中放置断点时,每次迭代都会返回正确的值。在我枚举之后,值都是一样的——截图如下:
上图:Select() 正确返回了投影值——每次迭代都返回一个完全不同的对象。
上图:枚举值都等于原始 GetFiles() 调用的最后一个元素,您可以通过 Locals 窗口中的两个展开元素看到。
这是我的测试(调用 GetService() 时将模拟插入到服务中,并在 nunit SetUp 方法中放置了许多全局设置):
[Test]
public void GetBlogPosts_PicksUpFilesInReverseFileNameDateOrder() {
// Arrange
var file1 = Path.Combine(blogPathContent, "2013-12-28-04-31-41-this-is-the-blog-title-1.json"); // 2
var file2 = Path.Combine(blogPathContent, "2013-10-09-01-54-43-this-is-the-blog-title-2.json"); // 3
var file3 = Path.Combine(blogPathContent, "2014-01-12-18-52-32-this-is-the-blog-title-3.json"); // 1
var file4 = Path.Combine(blogPathContent, "2012-12-20-06-18-23-this-is-the-blog-title-5.json"); // 5
var file5 = Path.Combine(blogPathContent, "2013-06-04-12-28-56-this-is-the-blog-title-4.json"); // 4
mockSerializer
.Setup(x => x.Deserialize<BlogPostModel>(It.IsAny<string>()))
.Returns(new BlogPostModel());
mockDirectory
.Setup(x => x.GetFiles(It.Is<string>(s => s == blogPathContent),
It.Is<string>(s => s == string.Concat("*", blogFilesExt))))
.Returns(new[] {file1, file2, file3, file4, file5});
service = GetService();
// Act
var actualResult = service.GetBlogPosts(new GetBlogPostsRequest());
// Assert
//mockFile1.VerifyGet(x => x.FullName, Times.Exactly(5), "FullName should have been called exactly 5 times.");
Assert.NotNull(actualResult.BlogList, "BlogList should not be null");
Assert.NotNull(actualResult.BlogList.BlogPosts, "BlogPosts should not be null");
Assert.True(actualResult.Success, "Success should be true");
Assert.IsNull(actualResult.Message, "Message should be null");
Assert.AreEqual(5, actualResult.BlogList.BlogPosts.Length, "5 blog posts are expected");
Assert.AreEqual(new DateTime(2014, 1, 12, 18, 52, 32), actualResult.BlogList.BlogPosts[0].FileDate, "file3 should be pos 1");
Assert.AreEqual(new DateTime(2013, 12, 28, 4, 31, 41), actualResult.BlogList.BlogPosts[1].FileDate, "file1 should be pos 2");
Assert.AreEqual(new DateTime(2013, 10, 9, 1, 54, 43), actualResult.BlogList.BlogPosts[2].FileDate, "file2 should be pos 3");
Assert.AreEqual(new DateTime(2012, 12, 20, 6, 18, 23), actualResult.BlogList.BlogPosts[4].FileDate, "file4 should be pos 5");
Assert.AreEqual(new DateTime(2013, 6, 4, 12, 28, 56), actualResult.BlogList.BlogPosts[3].FileDate, "file5 should be pos 4");
}
下面是实现代码:
public GetBlogPostsResponse GetBlogPosts(GetBlogPostsRequest req)
{
var files = _fs.Directory.GetFiles(contentPath, string.Concat("*", blogFilesExtension));
if (files == null || files.Length <= 0) {
return new GetBlogPostsResponse {
Success = false,
Message = "No blog posts have been made"
};
}
// Deserialize / map each message
var orderedFiles = files
.Select(p => {
var post = _serializer.Deserialize<BlogPostModel>(_fs.File.ReadAllText(p));
post.FileDate = GetFileNameDate(p);
post.FilePath = p;
return post;
})
.OrderByDescending(x => x.FileDate);
var posts = orderedFiles.ToArray();
var response = new GetBlogPostsResponse {
Success = true,
BlogList = new BlogListModel {
// BUG: enumerating here is returning a copy of the last element of the array for all elements
BlogPosts = posts
}
};
return response;
}
我是否遗漏了一些明显的东西?我检查了所有的模拟设置是否正确,上面的调试似乎表明 ToArray() 方法正在玩有趣的乞丐......但这不可能,对吧? :|
【问题讨论】: