【问题标题】:Contains functionality in Linq to XML Where Clause包含 Linq to XML Where 子句中的功能
【发布时间】:2011-06-06 20:25:12
【问题描述】:

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";

现在发生的情况是,如果 Query 完美运行

<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))

【问题讨论】:

  • 请检查我的新答案 - 原来的答案是错误的。

标签: c# .net linq-to-xml


【解决方案1】:

试试这个:

_filters.Any(s => ((string)sr.Element("itemtype") ?? "").Contains(s))

这样您就可以检查元素的值是否包含_filters 中的任何字符串。使用 null 合并运算符可确保当 itemtype 节点不存在时不会抛出 NullReferenceException,因为它被替换为空字符串。

另一种方法是使用let 并过滤掉空值:

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)

【讨论】:

  • 我遇到的问题是,如果项目未正确标记, 有时可能为空。如果元素为空,即 ,.Value 会抛出异常,这就是为什么我总是大小写为字符串而不是依赖于 .Value。
  • @Wesley 尝试更新的方法。这使用let 来保留显式转换结果,如果它为空,则将其过滤掉,然后检查过滤器项。
  • **EDIT 我尝试了这种方法,枚举出来完全是空的。不正确,它得出了一些结果,但不是全部。
  • @Wesley 在您发表评论之前,我在帖子底部又添加了一项更新。您的过滤器或值可能包含大小写混合。使用我上面概述的IndexOf 方法来忽略过滤器和元素值的大小写。如果这不起作用,那么问题出在其他地方。
  • 艾哈迈德,确实有一个案例问题是另一个团队的不良代码的一部分。这已得到修复,所有 XML 都设置为小写。您的解决方案有效,但其他人的速度更快,他们的代码更简洁,所以我将他们的标记为答案。不过我会赞成,你做得很好。
【解决方案2】:

您正在检查数组_filters 是否有一个值为"videos mission critial document advertising" 的元素(不是这种情况),而不是检查"videos mission critial document advertising" 是否包含_filters 中的任何元素。

试试这个:

where _filters.Any(filter => ((string)sr.Element("itemtype")).Contains(filter))

【讨论】:

  • 我不认为这是真的,如果节点 包含像 videos 这样的单个值,那么 Linq 会返回该节点,而不是来自 _filters 的字符串。
  • 有趣。所以我尝试了你的代码,现在我必须解决相反的问题。只是 videos 的节点会被忽略,而像 marketing communication videos 这样的节点会被接受。真是一头雾水。
  • 如果结果是null,这里使用Contains 会抛出NullReferenceException。我已经更新了我的回复来处理这种情况。
【解决方案3】:

问题在于您对Contains 方法的工作方式做出了错误的假设。 (另请参阅String.Contains() documentation 如果“序列包含特定元素”,则 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
        };

查看此帖子也可能会有所帮助:How do I use LINQ Contains(string[]) instead of Contains(string),它与此类似,但专门针对 String.Contains 方法而不是 Enumerable.Contains 扩展。

【讨论】:

  • .ContainsAny 现在对我来说不是一个可用的选项。如果这有什么不同,我就在 Silverlight,但我检查以确保我的 .NET 框架是版本 4。
  • @Wesley,你是什么意思它不可用?我发布了代码。将其复制并粘贴到您的解决方案中。
  • 我愿意,并且 ContainsAny 显示“字符串不包含 ContainsAny 的定义”。我现在正在研究这个。
  • @Ahmad Mageed 您的意思是单独的 LINQ 语句。这就是我现在正在做的事情,但是使用两个语句 where 一个带有正确 Where 的语句似乎很愚蠢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
相关资源
最近更新 更多