为什么List <int>不能在xunit.net理论中转换为TCollection?</int>

时间:2015-02-18 10:51:50

标签: c# generics xunit xunit.net

我正在尝试在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" } }
    };

当我尝试执行此理论时,抛出以下异常:&#34; System.ArgumentException:类型&#39; List&#39; 1 [System.String] / List&#39; 1 [System.Int32]&#39;无法转换为类型&#39;列出&#39; [System.Object]&#39;。&#34; (我缩短并合并了两个例外的文本)

我知道这可能与参数类型有关,因为它不是直接的泛型类型,而是使用嵌套泛型的类型。因此,我以下列方式改变了测试:

[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>运行会产生以下异常:&#34; System.ArgumentException:GenericArguments [1],&#39;列表&#39; 1 [System.Int32]&#39;,on&#39; AddRangeTest2&#39;违反了类型&#39; TCollection&#39;。&#34; 的限制(再次,我将异常文本缩短到相关点)

我的实际问题是:为什么在通用理论中可以使用List<string>而不是List<int>这两种类型都满足{{1}的约束我认为是通用的。

如果我将TCollection更改为List<int>,那么一切正常 - 因此我认为它与值类型/参考类型和协变/反演有关。

我使用xunit 2.0.0-rc2虽然我也观察到了rc1的这种行为 - 因此我认为它与版本无关(甚至可能不是xunit的问题)。如果您想查看完整的源代码,可以从my dropbox下载(我使用VS 2013创建)。请将此代码视为MCVE

非常感谢您的帮助!

关闭此问题后进行修改: Cannot convert from List<DerivedClass> to List<BaseClass>未回答我的问题,因为我根本没有使用基于继承的强制转换 - 而是相信xunit.net使用泛型这是通过反思解决的。

1 个答案:

答案 0 :(得分:1)

无论你做什么,它仍然归结为在幕后进行IEnumerable<int>IEnumerable<object>转换的事实。

您似乎假设通用参数是根据给定的具体输入填充的。

事实并非如此。泛型类型参数是从MemberData中引用的变量推导出来的,而不是它所持有的实际内容,因此,您的测试方法将始终调用下一个签名:

 AddRangeTest2<object, object[]>(object[] items)

上述签名支持隐式 引用类型的协方差(意思是:您可以将string[]传递给此方法,但不能传递int[])。

Covariance for value types is not supported

<小时/> 这就是说,如果xUnit足够聪明,可以根据实际输入指定正确的泛型类型参数,那将会很酷。我自己没有使用xUnit的经验,也许已经有办法了吗?如果没有,请在codeplex中提供功能请求,或者自己做+拉请求;)