今天我遇到了与C#相关的问题。我必须编写一个程序来通过一些测试。我实现的一切都正常工作,但有一个测试不允许使用公共字段,但它失败了。
我有一个实现IEnumerable的泛型类,导致问题的是:
public IEnumerator<R> GetEnumerator()
{
foreach (R r in roomList)
yield return r;
}
如果我把这个类“返回null”,测试通过正常。我想知道什么是错的?这是一份测试报告:
Result Message: Assert.Fail failed. Detected type "Exercise.Hotel`2+<GetEnumerator>d__0" with public filed(s) "Exercise.Hotel`2[R,SC] <>4__this, R <r>5__1, Enumerator <>7__wrap2", which is not allowed.
这里也是测试代码。说实话,我不太熟悉它是如何工作的。当然也可能是由于测试不好造成的。
var withPublicField = types.Where(t => !t.IsEnum)
.Where(t => t.GetFields(BindingFlags.Public | BindingFlags.Instance).Count() > 0)
.Where(t => !t.Name.StartsWith("<>c__DisplayClass"))
.ToDictionary(t => t.FullName, t => t.GetFields(BindingFlags.Public | BindingFlags.Instance));
感谢您的帮助。这是我的第一个问题所以我希望我做得很好:)
答案 0 :(得分:5)
这是你正在谈论的一个奇怪的考验。
迭代器方法(即其中包含yield return
的方法)触发失败的原因是C#编译器重写此类方法以返回将该方法实现为状态机的隐藏类的实例。这种类型中包含不允许的公共字段。
就个人而言,我认为失败是误报。虽然我同意公共字段通常是令人厌恶的,但在这种情况下,您正在处理隐藏的,编译器生成的代码。这种特殊情况应该没问题。
希望你能在这种情况下抑制失败,并解释“这不是我的错!”另一种方法是实现自己的类,为场景实现IEnumerator<T>
类型,当然不包含公共字段。
编辑:我注意到测试代码已经尝试排除编译器生成的捕获变量代码(即Name.StartsWith("<>c__DisplayClass")
)。因此,测试作者可能会为编译器生成的<GetEnumerator>
类型添加类似的排除(当然,根据Lee的答案检查[CompilerGenerated]
)。
答案 1 :(得分:4)
您可能希望忽略编译器生成的类,这些类应使用CompilerGeneratedAttribute
:
var withPublicField = types
.Where(t => !t.IsEnum)
.Where(t => Attribute.GetCustomAttribute(t,typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)) == null)
...