C# 如何检查具有特定值的项目是否是SelectList的一部分?

C# 如何检查具有特定值的项目是否是SelectList的一部分?,c#,asp.net-mvc,C#,Asp.net Mvc,在为一个带有SelectList属性的模型编写单元测试时,我有点不知所措。我将我的情况归结为以下单元测试: [Test] public void SanityCheck() { var rawOptions = new[] { (int?)null, 0, 1 }; var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a.ToString() })); Asse

在为一个带有
SelectList
属性的模型编写单元测试时,我有点不知所措。我将我的情况归结为以下单元测试:

[Test]
public void SanityCheck()
{
    var rawOptions = new[] { (int?)null, 0, 1 };
    var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a.ToString() }));
    Assert.That(selectList.Count(item => item.Value == null), Is.EqualTo(1));
}
该测试失败(“预期1,实际3”)。但为什么

经过一段时间的尝试,我意识到
selectList
实际上是一个
selectList
,因此我尝试将测试更改为更具体的测试:

[Test]
public void SanityCheck()
{
    var rawOptions = new[] { (int?)null, 0, 1 };
    var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a.ToString() }));
    Assert.That(selectList.Items.Count(item => item.Value == null), Is.EqualTo(1));
}
编译失败,并显示以下消息:

“System.Collections.IEnumerable”不包含“Count”的定义,并且找不到接受“System.Collections.IEnumerable”类型的第一个参数的扩展方法“Count”(是否缺少using指令或程序集引用?)

我可以理解,因为
Items
属性是非泛型
IEnumerable
类型。但现在我不知道该如何编写我的
Assert
选择列表
上没有
属性或任何类似属性

我错过了什么?如果我将动态对象用于我的
选择列表
,这是不可能的吗?有什么建议吗


起初我以为我省略了使用System.Linq的
在我的文件中,但它在那里。为了确保没有副作用导致我的问题,我在一个可再现的场景中执行了以下操作以获得上述结果:

  • 在VS 2012中,创建一个新的.NET 4.5类库项目
  • 使用NuGet添加NUnit 2.6.4
  • 使用NuGet添加Microsoft ASP.NET MVC 5.2.3(以及提到的依赖项)
  • 将下面的代码复制粘贴到自动创建的
    Class1.cs
    文件中:
  • 复制:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using NUnit.Framework;
    
    namespace ClassLibrary2
    {
        [TestFixture]
        public class Class1
        {
            [Test]
            public void SanityCheck1()
            {
                var rawOptions = new[] { (int?)null, 0, 1 };
                var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a.ToString() }));
                Assert.That(selectList.Count(item => item.Value == null), Is.EqualTo(1));
            }
    
            [Test]
            public void SanityCheck2()
            {
                var rawOptions = new[] { (int?)null, 0, 1 };
                var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a.ToString() }));
                // Will not compile:
                //Assert.That(selectList.Items.Count(item => item.Value == null), Is.EqualTo(1));
            }
        }
    }
    

    SelectList。项的类型为
    IEnumerable
    。为了能够对它执行linq查询,您需要将它转换为某种类型的强类型泛型
    IEnumerable

    但是,如果您像在示例中那样使用匿名类型,我认为这是不可能的。除非您愿意动态生成表达式,否则编译器需要知道您使用的类型。因为没有为非泛型的
    IEnumerable
    定义
    Count()
    ,这就是为什么会出现编译器错误

    相反地,
    SelectList
    本身继承了
    IEnumerable
    ,这是
    IEnumerable
    的一种通用类型,可以为其编写linq查询。我认为,当您以
    IEnumerable
    的形式访问
    SelectList
    实例时,在幕后
    SelectList
    会将您提供给
    SelectListItems.Items
    的匿名类型转换为
    SelectListItems
    实例

    您真的需要使用匿名类型来生成选择列表项吗?请尝试以下代码:

    [Test]
    public void SanityCheck()
    {
        var rawOptions = new[] { (int?)null, 0, 1 };
        var selectList = new SelectList(rawOptions.Select(a => new SelectListItem { Value = a.ToString(), Text = a.ToString() }));
        Assert.That(selectList.Items.Cast<SelectListItem>().Count(item => String.IsNullOrEmpty(item.Value)), Is.EqualTo(1));
    }
    
    [测试]
    public void SanityCheck()
    {
    var rawOptions=new[]{(int?)null,0,1};
    var-selectList=new-selectList(rawOptions.Select(a=>new-SelectListItem{Value=a.ToString(),Text=a.ToString()}));
    Assert.That(selectList.Items.Cast().Count(item=>String.IsNullOrEmpty(item.Value)),是.EqualTo(1));
    }
    

    请注意,
    selectList.Items.Cast()
    如果为
    selectList
    匿名类型提供数据,则运行时会失败。这表示
    SelectList.items
    中的项目在添加时会被保留。

    实际结果为3,因为您尚未设置
    SelectList项目的
    属性(它们都为空)。您正在使用接受
    IEnumerable
    SelectList
    构造函数的。这通常在集合为值类型时使用。例如:

    List<string> items = new List<string>() {"Option 1", "Option 2" };
    SelectList selectList = new SelectList(items);
    
    请注意,选项标记没有
    属性(这不是必需的,因为选择选项会将select的值设置为选项文本)

    如果您在本例中使用
    DropDownListFor()
    ,您将看到生成的输出有多奇怪(您有一组匿名对象,并且
    SelectList
    构造函数在内部调用每个项的
    ToString()
    方法)

    {Value=,Text=}
    {Value=0,Text=0}
    {Value=1,Text=1}
    
    您需要使用指定
    dataValueField
    dataTextField

    var selectList = new SelectList(rawOptions.Select(a => new { Value = a, Text = a }), "Value", "Text");
    
    也可能是

    var selectList = new SelectList(rawOptions.Select(a => new { ID = a, Name = a }), "ID", "Name");
    
    将生成以下html

    
    0
    1.
    
    但是,内部
    null
    值被转换为空字符串(生成html所必需),因此在这种情况下
    Assert
    也将失败,因为实际结果为零。相反,您需要检查是否有空字符串

    Assert.That(selectList.Count(item => item.Value == string.Empty), Is.EqualTo(1));
    

    在任何情况下,
    SelectList
    都不应包含“空”选项。相反,您应该使用接受
    标签选项的
    DropDownListFor()
    来生成
    null
    值。

    我知道您提到的最后一个选项,但我还不确定是否喜欢该选项,因为这会阻止我对视图是否正确显示显式选项进行单元测试“空”。无论如何:谢谢你的明确解释!