【问题标题】:My code is very inefficient for this simple Linq usage对于这种简单的 Linq 用法,我的代码效率很低
【发布时间】:2010-07-07 03:03:28
【问题描述】:

我有以下方法应该从 XML 响应中解析信息并返回用户集合。

我选择创建一个 Friend 类并将 List<Friend> 返回给调用方法。

这是我目前所拥有的,但我注意到 ids.ToList().Count 方法将每个 id 元素解析为一个列表,然后在 for 条件中再次执行此操作。实在是太没用了。

public List<Friend> FindFriends()
{
    List<Friend> friendList = new List<Friend>();

    var friends = doc.Element("ipb").Element("profile").Element("friends").Elements("user");
    var ids = from fr in friends
              select fr.Element("id").Value;

    var names = from fr in friends
                select fr.Element("name").Value;

    var urls = from fr in friends
                select fr.Element("url").Value;

    var photos = from fr in friends
                select fr.Element("photo").Value;

    if (ids.ToList().Count > 0)
    {
        for (int i = 0; i < ids.ToList().Count; i++)
        {
            Friend buddy = new Friend();
            buddy.ID = ids.ToList()[i];
            buddy.Name = names.ToList()[i];
            buddy.URL = urls.ToList()[i];
            buddy.Photo = photos.ToList()[i];

            friendList.Add(buddy);
        }
    }            

    return friendList;
}

【问题讨论】:

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


    【解决方案1】:

    第一个问题 - 你必须返回 List&lt;Friend&gt; 吗?你可以返回一个IEnumerable&lt;Friend&gt; 吗?如果是这样,性能会好很多:

    IEnumerable<Friend> FindFriends()
    {
        return doc.Descendants("user").Select(user => new Friend {
            ID = user.Element("id").Value,
            Name = user.Element("name").Value,
            Url = user.Element("url").Value,
            Photo = user.Element("photo").Value
        });
    }
    

    这不是实际创建新的存储桶并将值填充到其中,而是创建一个投影,或者一个新对象,它只包含如何创建新的 Friend 对象而不实际创建它们。当调用者最终通过 IEnumerable 开始 foreach 时,它们会被创建。这称为“延迟执行”。

    这也做了一个假设——XML 片段中的所有&lt;user&gt; 节点都是朋友。如果不是这样,那么 XML 选择的第一部分可能需要稍微复杂一些。

    正如@anon 指出的那样,即使您确实需要返回List&lt;Friend&gt;,由于某种原因从您提供的信息中并不明显,您也可以在返回语句的末尾调用.ToList()。这只会将我上面描述的投影直接执行到一个新存储桶中,因此您只能创建一个。

    【讨论】:

    • 即使他们必须返回一个列表,在这个问题上调用 ToList() 也会比他们现在做的更好。
    • 我不用返回List,我只是习惯了。我似乎总是忘记 IEnumarable。谢谢,这段代码太棒了。我会测试一下,看看它是否有效。再次感谢!
    【解决方案2】:

    为什么需要单独的 ids/names/urls/photos 变量?把它结合起来。如果您不需要 List,则可以消除 ToList() 调用。

    List<Friend> friendList = (from f in doc.Element("ipb").Element("profile").Element("friends").Elements("user")
                              select new Friend() { 
                                                     ID = f.Element("id").Value, 
                                                     Name = f.Element("name").Value,
                                                     URL = f.Element("url").Value,
                                                     Photo = f.Element("photo").Value
                                     }).ToList();
    
    return friendList;
    

    【讨论】:

      猜你喜欢
      • 2015-04-25
      • 2016-05-02
      • 1970-01-01
      • 2020-06-16
      相关资源
      最近更新 更多