How to: Handle Exceptions in Query Expressions (C# Programming Guide)
It is possible to call any method in the context of a query expression. However, we recommend that you avoid calling any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general .NET Framework guidelines on exception handling. Those guidelines state that it is acceptable to catch a specific exception when you understand why it will be thrown in a given context. For more information, see Best Practices for Handling Exceptions.
The final example shows how to handle those cases when you must throw an exception during execution of a query.
Example
The following example shows how to move exception handling code outside a query expression. This is only possible when the method does not depend on any variables local to the query.
class ExceptionsOutsideQuery
{
static void Main()
{
// DO THIS with a datasource that might
// throw an exception. It is easier to deal with
// outside of the query expression.
IEnumerable<int> dataSource;
try
{
dataSource = GetData();
}
catch (InvalidOperationException)
{
// Handle (or don't handle) the exception
// in the way that is appropriate for your application.
Console.WriteLine("Invalid operation");
goto Exit;
}
// If we get here, it is safe to proceed.
var query = from i in dataSource
select i * i;
foreach (var i in query)
Console.WriteLine(i.ToString());
//Keep the console window open in debug mode
Exit:
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
// A data source that is very likely to throw an exception!
static IEnumerable<int> GetData()
{
throw new InvalidOperationException();
}
}
In some cases, the best response to an exception that is thrown from within a query might be to stop the query execution immediately. The following example shows how to handle exceptions that might be thrown from inside a query body. Assume that SomeMethodThatMightThrow can potentially cause an exception that requires the query execution to stop.
Note that the try block encloses the foreach loop, and not the query itself. This is because the foreach loop is the point at which the query is actually executed. For more information, see Introduction to LINQ Queries (C#).
class QueryThatThrows
{
static void Main()
{
// Data source.
string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };
// Demonstration query that throws.
var exceptionDemoQuery =
from file in files
let n = SomeMethodThatMightThrow(file)
select n;
// Runtime exceptions are thrown when query is executed.
// Therefore they must be handled in the foreach loop.
try
{
foreach (var item in exceptionDemoQuery)
{
Console.WriteLine("Processing {0}", item);
}
}
// Catch whatever exception you expect to raise
// and/or do any necessary cleanup in a finally block
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
//Keep the console window open in debug mode
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
// Not very useful as a general purpose method.
static string SomeMethodThatMightThrow(string s)
{
if (s[4] == 'C')
throw new InvalidOperationException();
return @"C:\newFolder\" + s;
}
}
/* Output:
Processing C:\newFolder\fileA.txt
Processing C:\newFolder\fileB.txt
Operation is not valid due to the current state of the object.
*/
Compiling the Code
Create a Visual Studio project that targets the .NET Framework version 3.5. By default, the project has a reference to System.Core.dll and a using directive for the System.Linq namespace.
Copy the code into your project.
Press F5 to compile and run the program.
Press any key to exit the console window.