KeyNotFoundException,但调试时不会出现
我一直在构建一个扩展库,并且使用了在 http://www.extensionmethod 中找到的出色扩展方法。 net 进行包含。在我的单元测试(使用 NUnit 1.5.2)中,我遇到了一个有趣的问题。首先,让我们看一下代码:
/// <summary>
/// Groups and aggregates the sequence of elements.
/// </summary>
/// <typeparam name="TSource">The source type in the sequence.</typeparam>
/// <typeparam name="TFirstKey">The first key type to group by.</typeparam>
/// <typeparam name="TSecondKey">The second key type to rotate by.</typeparam>
/// <typeparam name="TValue">The type of value that will be aggregated.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="firstKeySelector">The first key selector.</param>
/// <param name="secondKeySelector">The second key selector.</param>
/// <param name="aggregator">The aggregating function.</param>
/// <returns>A <see cref="Dictionary{TKey,TValue}" /> representing the pivoted data.</returns>
public static Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>> Pivot<TSource, TFirstKey, TSecondKey, TValue>
(this IEnumerable<TSource> source,
Func<TSource, TFirstKey> firstKeySelector,
Func<TSource, TSecondKey> secondKeySelector,
Func<IEnumerable<TSource>, TValue> aggregator)
{
return source.GroupBy(firstKeySelector).Select(
x => new
{
X = x.Key,
Y = x.GroupBy(secondKeySelector).Select(
z => new { Z = z.Key, V = aggregator(z) }).ToDictionary(e => e.Z, o => o.V)
}).ToDictionary(e => e.X, o => o.Y);
}
该函数的作用是接收类型为 TSource 的 IEnumerable,并将项目转入字典中,并使用您定义的任何函数聚合项目。我的样本数据集是一个人的数组(名为 Person 的类型)。
private static readonly Person[] people =
new[]
{
new Person { Forename = "Matt", Surname = "Someone", Email = "[email protected]", Age = 25, IsMale = true },
new Person { Forename = "Chris", Surname = "Someone", Email = "[email protected]", Age = 28, IsMale = false },
new Person { Forename = "Andy", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true },
new Person { Forename = "Joel", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true },
new Person { Forename = "Paul", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true }
};
最后,我们进行测试:
/// <summary>
/// Performs a pivot function on the sample array.
/// </summary>
[Test]
public void Pivot()
{
/* Our sample data is an array of Person instances.
* Let's organise it first by gender (IsMale), and then by Age.
* Finally, we'll return a count. */
var organised = people.Pivot(p => p.IsMale, p => p.Age, l => l.Count());
Assert.IsTrue(organised.Count == 2, "More than two genders were returned.");
Assert.IsTrue(organised[true].Count == 2, "More than two ages were returned for males.");
Assert.IsTrue(organised[false].Count == 1, "More than 1 age was returned for females.");
int count = organised[true][30];
Assert.IsTrue(count == 3, "There are more than 3 male 30 year olds in our data.");
}
在这个测试用例中返回的是一个 Dictionary> 。实例。布尔值是 IsMale group by 的结果,在我们的示例数据中,正确返回 2 项,true 和 false。内部字典有一个年龄键和一个计数值。在我们的测试数据中,organized[true][30] 反映了集合中所有 30 岁的男性。
问题不在于数据透视函数本身,而是由于某种原因,当我们通过 NUnit 测试运行程序和 Resharper 的单元测试运行程序运行此函数时,测试失败,报告行“int count =organized[true][”的 KeyNotFoundException 30];”。当我们调试此测试时,它正确返回值 3(在我们的示例数据中,我们有 3 名 30 岁的男性)。
有什么想法吗?
I've been building an extensions library, and I've utilised a great extension method found at http://www.extensionmethod.net for inclusion. In my unit test (using NUnit 1.5.2), I've come across an interesting issue. Firstly, lets look at the code:
/// <summary>
/// Groups and aggregates the sequence of elements.
/// </summary>
/// <typeparam name="TSource">The source type in the sequence.</typeparam>
/// <typeparam name="TFirstKey">The first key type to group by.</typeparam>
/// <typeparam name="TSecondKey">The second key type to rotate by.</typeparam>
/// <typeparam name="TValue">The type of value that will be aggregated.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="firstKeySelector">The first key selector.</param>
/// <param name="secondKeySelector">The second key selector.</param>
/// <param name="aggregator">The aggregating function.</param>
/// <returns>A <see cref="Dictionary{TKey,TValue}" /> representing the pivoted data.</returns>
public static Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>> Pivot<TSource, TFirstKey, TSecondKey, TValue>
(this IEnumerable<TSource> source,
Func<TSource, TFirstKey> firstKeySelector,
Func<TSource, TSecondKey> secondKeySelector,
Func<IEnumerable<TSource>, TValue> aggregator)
{
return source.GroupBy(firstKeySelector).Select(
x => new
{
X = x.Key,
Y = x.GroupBy(secondKeySelector).Select(
z => new { Z = z.Key, V = aggregator(z) }).ToDictionary(e => e.Z, o => o.V)
}).ToDictionary(e => e.X, o => o.Y);
}
What the function does, is takes in an IEnumerable of type TSource, and pivots the items into a dictionary, and aggregates the items using whatever function you define. My sample set of data is an array of people (in a type called Person).
private static readonly Person[] people =
new[]
{
new Person { Forename = "Matt", Surname = "Someone", Email = "[email protected]", Age = 25, IsMale = true },
new Person { Forename = "Chris", Surname = "Someone", Email = "[email protected]", Age = 28, IsMale = false },
new Person { Forename = "Andy", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true },
new Person { Forename = "Joel", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true },
new Person { Forename = "Paul", Surname = "Someone", Email = "[email protected]", Age = 30, IsMale = true }
};
And lastly, we do our test:
/// <summary>
/// Performs a pivot function on the sample array.
/// </summary>
[Test]
public void Pivot()
{
/* Our sample data is an array of Person instances.
* Let's organise it first by gender (IsMale), and then by Age.
* Finally, we'll return a count. */
var organised = people.Pivot(p => p.IsMale, p => p.Age, l => l.Count());
Assert.IsTrue(organised.Count == 2, "More than two genders were returned.");
Assert.IsTrue(organised[true].Count == 2, "More than two ages were returned for males.");
Assert.IsTrue(organised[false].Count == 1, "More than 1 age was returned for females.");
int count = organised[true][30];
Assert.IsTrue(count == 3, "There are more than 3 male 30 year olds in our data.");
}
What is being returned in this test case, is a Dictionary> instance. The boolean is a result of the IsMale group by, and in our sample data, correctly returns 2 items, true and false. The inner dictionary has a key of the age, and a value of the count. In our test data, organised[true][30] reflects all males of the age of 30 in the set.
The problem is not the pivot function itself, but for some reason, when we run this through both the NUnit Test Runner, and Resharper's Unit Test Runner, the test fails, reporting a KeyNotFoundException for the line "int count = organised[true][30];". When we debug this test, it correctly returns the value 3 (as in our sample data, we have 3 males of the age 30).
Any thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您是否尝试将 NUnit 配置为从 VS 内运行它(作为外部程序)?这样您就可以让 NUint 运行您的测试。在调试器下
Did you try to configure NUnit to run it from within VS (as an external program)? This way you will be able to have NUint run your test. under debugger