我试图用xunit.net编写一个泛型理论,它通过MemberDataAttribute使用集合。请查看以下代码:
[Theory]
[MemberData("TestData")]
public void AddRangeTest<T>(List<T> items)
{
var sut = new MyCustomList<T>();
sut.AddRange(items);
Assert.Equal(items, sut);
}
public static readonly IEnumerable<object[]> TestData = new[]
{
new object[] { new List<int> { 1, 2, 3 } },
new object[] { new List<string> { "Foo", "Bar" } }
};当我试图执行这个理论时,会引发以下异常:"System.ArgumentException: Object of type‘List’1 System.String/List‘1System.Int 32’不能转换为‘List’System.Object‘。“(我缩短并合并了两个异常的文本)。
我知道这可能与参数类型有关,因为它不是直接泛型类型,而是使用嵌套泛型的类型。因此,我以以下方式对测试进行了转换:
[Theory]
[MemberData("TestData")]
public void AddRangeTest2<T, TCollection>(TCollection items)
where TCollection : IEnumerable<T>
{
var sut = new MyCustomList<T>();
sut.AddRange(items);
Assert.Equal(items, sut);
}在本例中,我引入了一个名为TCollection的泛型,它与IEnumerable<T>实例相反。当我执行此测试时,List<string>运行有效,但是List<int>的运行会产生以下异常:"System.ArgumentException: GenericArguments1,‘List’1System.Int 32‘,on 'AddRangeTest2’违反了“TCollection”类型的约束。“(再次将异常文本缩短到相关点)。
我的实际问题是:为什么在泛型理论中可以使用List<string> List<int> 而不能使用List<int>呢?在我看来,这两种类型都满足TCollection泛型的约束条件。
如果我将List<int>更改为List<object>,那么一切都会正常工作--因此我假设它与值类型/引用类型和协/反方差有关。
我使用xunit 2.0.0-rc2,尽管我在rc1中也观察到了这种行为,因此我认为它是与版本无关的(甚至可能不是xunit的问题)。如果您想查看完整的源代码,可以从我的垃圾箱下载它(我是用VS 2013创建的)。请将此代码视为MCVE。
提前谢谢你的帮助!
在这个问题结束后,编辑:,我的问题没有被列出回答,因为这里我根本不使用基于继承的强制转换,相反,我认为xunit.net使用通过反射解决的泛型。
发布于 2015-02-18 12:48:55
无论您做什么,它仍然归结为这样一个事实,即在幕后正在进行IEnumerable<int>到IEnumerable<object>的转换。
您似乎假设泛型参数是根据给定的具体输入填充的。
情况并非如此。泛型类型参数是从MemberData中引用的变量中推导出来的,而不是它所包含的实际内容,因此,您的测试方法将是带有下一个签名的始终调用:
AddRangeTest2<object, object[]>(object[] items)上面的签名支持隐式对引用类型的协方差(意思是:可以将string[]传递给此方法,但不能传递int[])。
这就是说,如果xUnit足够聪明,根据实际输入指定正确的泛型类型参数,那就太酷了。我本人没有使用xUnit的经验,也许已经有办法了?如果不是,请使用codeplex中的特性请求,或者自己编写+拉请求;)
https://stackoverflow.com/questions/28581769
复制相似问题