问题描述
|
我在Linq to XML中的where子句的.Contains()函数中遇到意外行为。似乎在字符串函数中的功能类似于\“ == \” not Contains()。
例:
var q = from sr in SearchResults.Descendants(\"Result\")
where _filters.Contains((string)sr.Element(\"itemtype\"))
orderby (string)sr.Element(\"ipitemtype\") ascending
select new SearchItem
{
//Create Object
ID = (string)sr.Element(\"blabla\"),}
_filters是字符串列表。假设它包含3个值:
_filters[0] = \"videos\";
_filters[1] = \"documents\";
_filters[2] = \"cat pictures\";
现在发生的是,如果
<itemtype>videos</itemtype>
是XML节点。
但是,如果节点是
<itemtype>videos mission critical document advertising</itemtype>,
IEnumerable返回空白,对我来说,它表示操作数的功能类似于\“ == \”而不是\“ Contains()\”。
知道我在做什么错吗?
dtb的获奖答案:
更换
where _filters.Contains((string)sr.Element(\"itemtype\"))
与
where _filters.Any(filter => ((string)sr.Element(\"itemtype\")).Contains(filter))
解决方法
尝试这个:
_filters.Any(s => ((string)sr.Element(\"itemtype\") ?? \"\").Contains(s))
这样,您可以检查元素的值是否包含_filters
中的任何字符串。使用空合并运算符可确保在不存在itemtype
节点时不抛出NullReferenceException
,因为将其替换为空字符串。
另一种方法是使用ѭ10并滤除null:
var q = from sr in SearchResults.Descendants(\"Result\")
let itemtype = (string)sr.Element(\"itemtype\")
where itemtype != null &&
_filters.Any(filter => itemtype.Contains(filter))
orderby (string)sr.Element(\"ipitemtype\") ascending
select new SearchItem
{
//Create Object
ID = (string)sr.Element(\"blabla\")
}
请注意,String.Contains
区分大小写。因此,对\“视频\”的检查在\“视频\”上的大写\“ V \”不匹配。要忽略大小写,可以按以下方式使用String.IndexOf
:
_filters.Any(filter => itemtype.IndexOf(filter,StringComparison.InvariantCultureIgnoreCase) >= 0)
, 您正在检查数组_filters
是否具有值为\"videos mission critial document advertising\"
的元素(不是这种情况),而不是检查\"videos mission critial document advertising\"
是否包含_filters
中的任何元素。
尝试这个:
where _filters.Any(filter => ((string)sr.Element(\"itemtype\")).Contains(filter))
, 问题是您对Contains方法的工作方式做出了错误的假设。 (另请参见String.Contains()
文档,如果\“一个序列包含特定元素\”,则contains方法将返回true。在您描述的示例中,_filters
数组和itemtype
文本都包含字符串videos
,但彼此都不包含。更多适当的测试将使用以下扩展方法:
public static class ContainsAnyExtension
{
public static bool ContainsAny<T>(this IEnumerable<T> enumerable,params T[] elements)
{
if(enumerable == null) throw new ArgumentNullException(\"enumerable\");
if(!enumerable.Any() || elements.Length == 0) return false;
foreach(var element in elements){
if(enumerable.Contains(element)){
return true;
}
}
return false;
}
}
因此,正确的LINQ查询将是:
var q = from sr in SearchResults.Descendants(\"Result\")
where ((string)sr.Element(\"itemtype\")).ContainsAny(_filters)
orderby ((string)sr.Element(\"ipitemtype\")) ascending
select new SearchItem
{
ID = sr.Element(\"blabla\").Value
};
回顾这篇文章也可能会有所帮助:我如何使用LINQ Contains(string [])而不是Contains(string),后者类似,但是专门针对String.Contains
方法而不是Enumerable.Contains
扩展名。