2

I'm trying to use LINQ to return the top 5 ping results from an ObservableCollection<PingReply> but the resulting IEnumerable has a count of 0.

Can anyone explain why the lastFive object in the code below returns a count of 0 when .Take(5) is applied to PingReplies?

When a ping is sent, the PingReplies collection get's that object in the ObservableCollection

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.NetworkInformation;
using System.Collections.ObjectModel;

namespace XXX.ServerMonitor.Servers
{
    class WindowsServer : IServer
    {
        public WindowsServer(string address)
        {
            this.Address = address;
            PingReplies = new ObservableCollection<PingReply>();
            PingReplies.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(PingReplies_CollectionChanged);
        }

        void PingReplies_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                IEnumerable<PingReply> lastFive = PingReplies.Take(5);
                if (lastFive.Where(a => a.Status != IPStatus.Success).Count() == 5)
                {
                    // 5 failed attempts
                    // Server may be down
                    Console.WriteLine(Address + " may be down");
                }
            }
        }

        public ObservableCollection<PingReply> PingReplies { get; set; }

        PingReply IServer.Ping()
        {
            PingReply reply = Utils.Ping.Send(this.Address);
            PingReplies.Add(reply);
            return reply;
        }

        public string Address { get; set; }
    }
}

enter image description here

Edit: Actual code uploaded

Darbio
  • 11,286
  • 12
  • 60
  • 100
  • 3
    You might check the logic: you `Take` the *first* 5 and then count if there are 5 *or more* errors. – Hans Kesting Apr 26 '11 at 13:54
  • Yes, good spot (kind of) - this isn't the full logic. The full logic would be to take the final 5 from the list using `.Skip(PingReplies.Count - 5).Take(5)`. The `>= 5` is an artefact as currently `.Take()` returns a collection with 0 objects enumerated. `lastFive = PingReplies` – Darbio Apr 26 '11 at 13:57
  • 1
    Then please show _actual_ code that is in question, not some pseudo-incorrect piece that has to be excused when people poke holes in it. – Grant Thomas Apr 26 '11 at 14:02
  • 1
    JD, either Copy/Paste actual, compiling, code. Best if you can reproduce it in a small complete program. If the code is 'pseudo' then say so and use more `...` (Voted to close) – H H Apr 26 '11 at 14:43
  • Thanks for the comments guys. I have uploaded further code which is the entire class. As you can see, it is not much different. – Darbio Apr 27 '11 at 01:50

1 Answers1

3

If there is no data in the collection, Take returns no items. If there is actually some data around, you must have made some mistake in code you aren't showing us. Remember: select ain't broken ...

by the way, there is also a Reverse, instead of Skip(Count - x).Take(x).

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • Thanks for the tip wrt Reverse - that will be useful! There is data in the PingReplies collection when I step through with the debugger, however the Source is null and Count property is 0 on the `lastFive` variable. I have added a screenshot to the original question – Darbio Apr 27 '11 at 01:51
  • These `count` and `source` members you see aren't properties, they are fields. Don't care about them, it's internals of the `TakeIterator`. To see what's in there, write the following into the immediate window: `lastFive.ToArray()` – Stefan Steinegger Apr 27 '11 at 09:53
  • Thanks - that shows what is there. I was getting confused by the fields not showing what was expected. – Darbio Apr 27 '11 at 13:32