如何检查列表中是否存在某个值?

4
我相对于C#编程(实际上是整个编程)比较新,但我已经建立了一个应用程序来管理我们工作团队使用的服务器上的应用程序池。它很好地完成了所有它应该做的事情,但唯一遇到的问题是将先前使用的配置保存到app.config文件中,以便用户不必每次手动输入它们。目前,我可以很好地保存和加载文件(以及每个组中需要的所有字符串)。
问题在于,在写入之前,我想进行一个简要检查,以查看组中是否存在Name字符串。以下是app.config部分的示例:
<appSettings>
 <add Name="RowName" MachineName="MS-02348" AppSrvName="AppServer" WebSrvName="AppNet"/>
 <add Name="RowName2" MachineName="MS-68186" AppSrvName="AppServer2" WebSrvName="AppNet2"/>
</appSettings>

目前我正在做的是编写一个方法来获取 appSettings/add 节点并将它们放入一个列表中,然后将这些值设置为对象的属性。我这样做的原因是可以在下拉菜单中仅列出对象的名称,并且当我调用所选项目上的方法时,其余信息都是可用的。

无论如何,我现在遇到的问题是,如果在 app.config 中已经存在该名称,则要确保提示用户编写另一个名称而不是将其保存到数据库中。具有相同“名称”值的两个子节点会对我的逻辑造成严重影响。

我尝试使用 foreach 循环遍历列表中的对象,但由于不知道可能存在多少对象,我不知道是否存在一种简单的方式来判断它是否存在。我还尝试根据节点中列出的值来定位 childnode,但似乎也失败了。我猜这部分是语法问题,但它似乎与方法列表定义的方式相匹配。

您有什么想法吗?


2
你好,欢迎来到本站!有几件事情需要注意:你的示例代码中一个 MachineName 属性缺少了闭合引号;而且你应该包含实际处理列表的 C# 代码,并详细说明你遇到的具体问题。 - admdrew
“但是不知道可能有多少对象,我就不知道...” - 这句话的意思是什么?为什么这很重要? - ispiro
谢谢您的编辑。我没有复制和粘贴,所以可能错过了那个引用!我没有添加任何代码,因为它们都不能满足我的需求...不是因为无法编译或出现异常,而是我想不到一个逻辑上可行的方法来使其工作。我正在做的是一个foreach循环,然后比较每个结果,看看MachineName!= null(MachineName是任意的...只是确保没有返回任何内容)。问题在于它会返回3次false和1次true。在我的情况下,我希望确保所有都返回false。 - hotleadsingerguy
3个回答

12
if (list.Any()) 
{ 
   // found something! 
}
else 
{
   // found nothing 
}

我总是使用 Any(),因为它的性能最佳。 List.Count() 会遍历每个项目并对它们进行计数,但您只关心是否有任何一个项目存在,而不关心项目数量。 Any() 将枚举列表并在找到项目后停止枚举。 因此,在极端情况下,在包含一百万个项目的列表中,Count() 将枚举每个项目并返回,而 Any() 只会枚举一个项目并返回。

另外,它返回一个布尔值,这对于更简洁的代码非常方便。 :)

作为额外的奖励,您可以调用 Any() 查找特定内容。 因此,在一个人员列表中,我可以查看是否有年龄大于21岁的人:

if (list.Any(person => person.Age > 21))
{
   // ...
}

编辑:格式。


搞定了!我使用的基本代码如下:ConnectionInfo.GetConnectionInfos() 是我的列表创建方法。if(ConnectionInfo.GetConnectionInfos().Any(info => info.Name == textBox4.Text)) { //Complain that one exists }textBox4 是添加到列表中的输入框之一。这就解决了问题!感谢大家提供的绝妙建议! - hotleadsingerguy

6
也许类似这样的东西。
        var list = new List<AppSettings>();
        var item = list.FirstOrDefault(x => x.Name == NameEnteredByUser);
        if (item == null)
        {
            //there is no such item
        }
        else
        {
           //notify the user
        }

任何扩展方法的使用方法如下:

 var list = new List<AppSettings>();
        if (list.Any(x => x.Name == NameEnteredByUser))
        {
            //name exists
        }
        else
        {
            //no such name used before
        }

作为附注,需要在您的数据库中配置一个唯一字段,以便当您的编程逻辑失败时不会输入记录。数据库中的损坏数据状态是不好的。

2
我认为你需要使用FirstOrDefault而不是First - kaptan
不是因为检查 vs null,所以不使用 firstordefault。如果没有找到元素,则 firstordefault 从基础构造函数返回一个对象而不是 null。在这种情况下,获取 null 表明未找到任何项。 - neo112
根据 MSDN (http://msdn.microsoft.com/library/bb535050(v=vs.110).aspx) 的说明,如果没有匹配的元素,First 将抛出 InvalidOperationException 异常。 - JleruOHeP
@neo112 - 我认为kaptan是正确的,当你执行First()时,如果结果集为空,我的期望是它会抛出异常。无论如何,FirstOrDefault仍然更安全。 - Kaushal De Silva
是的,除非你明确处理异常,否则你总是想使用XOrDefault版本。如果没有内容,它们将返回null。在你的例子中,在if语句之前会抛出异常。话虽如此,Any()是一个更好的方法。 - Ari Roth
谢谢指出FirstOrDefault的情况,我把一些东西搞混了。 - neo112

2

neo112的逻辑是正确的,但我不确定您主要遇到的问题是否与性能有关,因为您提到不知道它是否会变得太长。

首先,您还可以执行以下操作:

int count = list.Count(a => a.Name == NameEnteredByUser);
if(count > 0)
{
    // exists
}

我认为.Count()比.First()更快(仅有经验证据),并且我个人认为它更加简洁。此外,你可以尝试在向appSettings节点添加时按名称对列表进行排序。然后,你应该实例化SortedList而不是仅仅的List,这也会(积极地)影响性能。但是,我不确定排序是否适用于你。

2
使用list.Any比使用list.Count更快。 - Darren Young
list.Count() 的时间复杂度为 O(n),而 list.Any 的最坏情况时间复杂度也是 O(n),因此在性能上你不会获胜。 - neo112
@DarrenYoung 很好的观点,我总是忘记 .Any()。这样更简洁。 - Kaushal De Silva
理论上,neo112 使用标准的 O-notation 是正确的。但实际上,如果你在一个大集合上调用 Count()Any() 时包含一个 lambda 表达式(例如下面的示例),差异可能会非常明显。对我来说,Any() 更好一些。 - Ari Roth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接