Nyra
Nyra

Reputation: 897

LINQ lambda expression throws Sequence contains no elements

I know what this error means, but I am not sure how to fix it in my LINQ statements.

ScannerMessages is a dictionary . The values in this will either be numeric from a serial scan, or string.empty, or (before any scans happen) null. I have a feeling someone will say to use FirstorDefault(), but I can't use the default value of null/string.empty. I tried using

.Any(x => !string.IsNullOrEmpty(x.Value)). 

but this returns a bool and is the wrong check. I feel like I need a Where() but I already tried that too to no avail (I also tried changing my GroupBy() clauses). I feel like I am close but I am not sure where to modify my expressions.

Note: This is inside a lock so I know none of my other threads are affecting the dictionary while I am querying against it (ScannerMessages is locked)

    public ScanType equalMessages()
    {
        try
        {
            lock (lckObj)
            {
                if (_scannersPresent)
                {
                    // Check to see if message that came through was caught in the buffer. If it has it will be equal to the previous message.
                    if (ScannerMessages.GroupBy(x => x.Value).Where(x => x.Count() > 1).First().Key == _holdMsg) return ScanType.ClearBuffer;
                    // If all messages are null or empty no scan
                    else if (ScannerMessages.Values.All(s => string.IsNullOrEmpty(s))) return ScanType.NoScan;
                    // If there is only one scanner then all scans must be determined to be either MATNUM or a rescan of an LPN
                    else if (_ScannerCount == 1) return ScanType.DiscernScanType;
                    // If distinct count of non null/empty values is less than total count of all non null/empty values, then scan is good
                    else if (ScannerMessages.Values.Distinct().Count(v => !string.IsNullOrEmpty(v)) < ScannerMessages.Values.Count(v => !string.IsNullOrEmpty(v)))
                    {
                        // This condition is only met if there is more than one of the same scan, and therefore is not a reprint. Pad all values with '0's for proper MATNUM format
                        ScannerMessages = ScannerMessages.Where(x => !string.IsNullOrEmpty(x.Value)).ToDictionary(x => x.Key, x => x.Value.PadLeft(18, '0'));
                        return ScanType.GoodScan;
                    }
                    // If non null/empty counts is equal to one, and the message is not the same as previous scan, then message was not from buffer and is LPN for reprint
                    else if ((ScannerMessages.Values.Distinct().Count(v => !string.IsNullOrEmpty(v)) == 1) && (ScannerMessages.GroupBy(x => x.Value).Where(x => x.Count() > 1).First().Key != _holdMsg)) return ScanType.Reprint;
                    else return ScanType.NoScan;
                }
                return ScanType.NoScan;
            }
        }
        catch (Exception ex) {
            myEvents.raiseErrorMessageBox(ex.Message);
            throw new Exception(ex.Message, ex); }
    }

Edit: I am not sure which line is throwing the error- I think it is either the first if line or the final else if before the else return ScanType.NoScan. Those are the only statements using the First() call. The problem is this gets called about every half second so debugging it backs up. There are 3 threads accessing the ScannerMessages dictionary, and then the thread that calls this checking that dictionary. I am not sure how to debug it when I have 4 threads hitting it. The only thing I know is that it is* thread-safe :/ If I try to put a breakpoint on the first line, it hits so many times that while I'm stepping through I miss any "real" scans.

Upvotes: 0

Views: 1086

Answers (2)

Nyra
Nyra

Reputation: 897

I don't know if I need to re-word the question, but I was able to get it using this- if there are any modifications to "streamline" it that would be great- I feel that grabbing the kvp.Value.Vlaue is a little redundant but again I am not sure how to "answer" the problem specifically, and this gets me what I need.

class testing
{

    private Dictionary<string, string> dict = new Dictionary<string, string>();
    private Dictionary<string, string> _dict = new Dictionary<string, string>();
    private Dictionary<string, string> __dict = new Dictionary<string, string>();
    public testing() 
    {
        dict.Add("stringA", string.Empty);
        dict.Add("stringB", "123456");
        dict.Add("stringC", string.Empty);

        _dict.Add("stringA", string.Empty);
        _dict.Add("stringB", string.Empty);
        _dict.Add("stringC", string.Empty);

        __dict.Add("stringA", "654321");
        __dict.Add("stringB", "123456");
        __dict.Add("stringC", string.Empty);

        checkDict(dict, "dictionary1");
        checkDict(_dict, "dictionary2");
        checkDict(__dict, "dictionary3");


    }

    private void checkDict(Dictionary<string,string> myDict, string s)
    {
        try
        {
            var exam = dict.Where(x => !string.IsNullOrEmpty(x.Value)).ToDictionary(x => x.Key);
            foreach (var kvp in exam)
            {
                Console.WriteLine(kvp.Value.Value);

            }
        }
        catch(Exception ex)
        {
            eh(ex);
        }
    }

    private void eh(Exception ex)
    {
        Console.WriteLine(ex.Message);
        if (ex.InnerException != null) eh(ex.InnerException);
    }
}

Upvotes: 0

Euphoric
Euphoric

Reputation: 12849

ScannerMessages.GroupBy(x => x.Value).Where(x => x.Count() > 1).First()

So what if there is no group that contains more than 1 element? What do you think should happen?

You should really separate those conditions into smaller steps instead of trying to put everything in single expression. In this case I recommend using FirstOrDefault and and replace the condition with :

var value = ScannerMessages.GroupBy(x => x.Value).Where(x => x.Count() > 1).FirstOrDefault()
if (value != null && value.Key == _holdMsg) return ScanType.ClearBuffer;

Upvotes: 1

Related Questions