简体   繁体   中英

Is there any way to catch predicate in LINQ that caused exception?

Say I have some statements like:

List<string> list = new List<string> {"1", "1", "2", "3", "4"};
try
{
    Class1 c = new Class1
        {
            s1 = list.Single(s => s == "1"),
            s2 = list.Single(s => s == "2"),
            s3 = list.Single(s => s == "3"),
            s4 = list.Single(s => s == "4")
        };
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.Message);
}

And I definitely will go to the catch block with an error "The input sequence contains more than one element" at this line:

s1 = list.Single(s => s == "1")

So, I just curious, it there any way to display error predicate in catch block? This will be very useful to fix the bugs, if we'll see something like "There was a duplicate element "1" in sequence." or even full predicate in string format. Can I somehow view this information and display or log it?

If you really need info about predicate and it's parameters, then you can create your own Single extension method (it will be called instead of default method), which will actually wrap default Single call, but it will receive Expression (expression tree that represents the lambda expression) instead of Func (lambda expression):

public static T Single<T>(this IEnumerable<T> sequence, 
                          Expression<Func<T, bool>> predicate)
{
    try
    {
        return sequence.Single(predicate.Compile());
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine("Error on predicate " + predicate);
        throw;
    }            
}

On line s1 = list.Single(s => s == "1") it will throw an exception and write pretty error message:

Error on predicate s => s == "1"

No, The exception thrown ( InvalidOperationException ) is generic and won't give that sort of detail. The stack trace will start at Single() and not show the predicate that was passed in.

If you need that level of detail you could either set the properties in separate statements so that you can get the line number from the stack trace, or you could do a "pre-check" of the data to make sure it meets your conditions for uniqueness.

List<string> list = new List<string> {"1", "1", "2", "3", "4"};
string sValue=null;
try
{
    sValue="1";
    Class1 c = new Class1
    {
       s1 = list.Single(s => s == sValue),

    };
}
catch (InvalidOperationException ex)
{
    Console.WriteLine("s => s == "+ sValue);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM