Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why was exception not caught within the closure? [duplicate]

Here is the code example:

    public IList<LogEntry> ReadLogs(Guid id, string name)
    {
        var logs = this.RetrieveLogs(id, name);

        if (logs != null)
        {
            foreach (LogEvent logEvent in logs)
            {
                // bla, bla, bla
            }
        }

        return logEntries;
    }

    private IEnumerable<LogEvent> RetrieveLogs(Guid id, string name)
    {
        try
        {
            FilterCriteria filterCriteria = CreateFilterCriteria();
            return (from log in this.loggingProvider.ReadLogs(filterCriteria, 1)
                    where log.ParticipantObjects[0].ParticipantObjectId ==  id.ToString() 
                     && log.LogEventParameters[0].Value == name
                    orderby log.Timestamp.ToLocalTime() descending
                    select log).AsEnumerable();
        }
        catch (Exception ex)
        {
            this.tracer.Write(Category.Error, ex, "Error");
            return null;
        }
    }

Now, if there was an exception inside of loggingProvider.ReadLogs() method, it will be caught and traced. But if, for example, there is no ParticipantObjects[0], this exception won't be caught and traced here. It seems that it has something to do with lambda expressions and closures.

What is the explanation?

like image 810
Nenad Dobrilovic Avatar asked Feb 11 '16 16:02

Nenad Dobrilovic


People also ask

What happens if an exception is not caught in a method?

What happens if an exception is not caught? If an exception is not caught (with a catch block), the runtime system will abort the program (i.e. crash) and an exception message will print to the console.

Which exception can not be caught?

Exceptions that Can't be Caught One such exception is the limit exception ( System. LimitException ) that the runtime throws if a governor limit has been exceeded, such as when the maximum number of SOQL queries issued has been exceeded.

Can an exception be caught twice?

Java does not allow us to catch the exception twice, so we got compile-rime error at //1 .

What happens if an exception does not have a matching catch clause?

If an exception does not have a matching catch clause, the current method terminates and throws the exception to the next higher level. If there is no matching catch clause at any higher level, then the program terminates with an error. Your program can do anything with the exception object that it chooses to.


3 Answers

I have said it before and I will undoubtedly say it again: the most important thing to know about a query is that a query is a question, not the answer to the question.

The query object you've built does not execute merely by building it. You are building the question. The question does not actually get asked and answered until you execute the query. And the execution is outside the try block.

like image 75
Eric Lippert Avatar answered Nov 04 '22 21:11

Eric Lippert


loggingProvider.ReadLogs is executed inside RetrieveLogs. But all the other lambdas are executed only when you iterate over them in the outer this.ReadLogs.

So the exception is thrown in your upper method, and so cannot be catched inside RetrieveLogs.

To avoid this, change AsEnumerable to ToList() or ToArray() to ensure the query is actually executed before returning.

like image 24
René Vogt Avatar answered Nov 04 '22 21:11

René Vogt


An IEnumerable result from a LINQ query is only evaluated when it is enumerated.

In order for the Exception to be thrown where you expect, you need to enumerate the LINQ query result IEnumerable using one of the relevant extension methods like ToList().

As a side-note (borrowing from Rene Vogt) you could avoid the Exception being thrown by writing your LINQ as follows:

return this.loggingProvider.ReadLogs(filterCriteria, 1).Where(log => 
    log.ParticipantObjects.FirstOrDefault() != null &&
    log.ParticipantObjects[0].ParticipantObjectId == id.ToString() &&
    log.LogEventParameters[0].Value == name).OrderBy(log => 
    log.Timestamp.ToLocalTime()).ToList();
like image 3
toadflakz Avatar answered Nov 04 '22 23:11

toadflakz