0

Which factory method in System.Linq.Expressions.Expression should I call to create an expression tree -- more specifically, a CatchBlock instance -- which represents the catch in the following C# code:

try {
    // ...
} catch {
    // ...
}

All the overloads of the Catch method seem to require either an exception type -- the equivalent of this:

catch (Exception) {
    // ...
}

and/or a ParameterExpression which will be bound to the exception -- the equivalent of this:

catch (Exception ex) {
    // ...
}

Passing null into the first argument (and casting to Type to avoid ambiguity):

// using static System.Linq.Expressions.Expression

Catch((Type)null, Constant(true));

causes an ArgumentNullException.

The MakeCatchBlock method has the same behavior

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
  • What would you catch if not a `System.Exception`? – Camilo Terevinto Mar 31 '19 at 13:11
  • 1
    AFAIK (and according to [this post](https://stackoverflow.com/a/8901166/3094533) as well), `try {...} catch {...}` is equivalent to `try {...} catch(Exception) {...}` - so you can simply create a `catch(Exception) {...}` expression instead of `catch {...}` expression. – Zohar Peled Mar 31 '19 at 13:11
  • 1
    @CamiloTerevinto It seems that a plain `catch` is a [valid way of handling non-CLS exceptions](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/how-to-catch-a-non-cls-exception), which may not inherit from `System.Exception`. – Zev Spitz Mar 31 '19 at 13:27
  • 1
    @ZoharPeled The [documentation](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/how-to-catch-a-non-cls-exception) indicates otherwise -- a plain `catch` will handle a non-CLS exception. – Zev Spitz Mar 31 '19 at 13:29
  • [This answer](https://stackoverflow.com/a/37721520/2141621) in the link @ZoharPeled provided, suggests that behavior changed in .NET 3.0. Also, are you hitting a 3rd party, non .NET library? – Camilo Terevinto Mar 31 '19 at 13:29
  • 1
    @CamiloTerevinto That answer has no references in support of its' claims, and the documentation page I linked to has been updated a number of times since .NET 3.0. [This answer](https://stackoverflow.com/a/8900991/111794) from the same question references the documentation page. – Zev Spitz Mar 31 '19 at 13:35
  • @CamiloTerevinto _are you hitting a 3rd party, non .NET library_ Not quite. I've written a library which [renders expression trees as strings](https://github.com/zspitz/ExpressionToString#string-representations-of-expression-trees), and I'm writing unit tests for this scenario. But I need to create such a `CatchBlock` first. – Zev Spitz Mar 31 '19 at 13:37
  • @ZevSpitz Did you read the page you've linked to? It does not have a `try {...} catch {...}` block but a `try {...} catch(RuntimeWrappedException e) {...}` block. The `RuntimeWrappedException` class inherits `Exception` directly.... – Zohar Peled Mar 31 '19 at 13:38
  • 1
    @ZoharPeled Did you read past the first bullet point? _In C# you cannot throw non-CLS exceptions, but you can catch them in two ways: ... * Within a general catch block (a catch block without an exception type specified) that is put after all other catch blocks._ – Zev Spitz Mar 31 '19 at 13:40
  • Citation here: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.runtimewrappedexception > .NET 2.0 onwards and since you are using LINQ, introduced in .NET 3.5, there is absolutely no way you will get problems with System.Exception – Camilo Terevinto Mar 31 '19 at 13:40
  • "To maintain compatibility between languages, the common language runtime (CLR) wraps objects that do not derive from Exception in a RuntimeWrappedException object.". (from the link provided by Camilo) – Zohar Peled Mar 31 '19 at 13:42
  • @ZoharPeled But C# allows you to write code that ignores any information in the exception wrapped inside the `RuntimeWrappedException` by using a plain `catch`. If it is possible to create a `CatchBlock` instance which represents this kind of code, I would like to do so and create a unit test for it. – Zev Spitz Mar 31 '19 at 13:51
  • 1
    @ZevSpitz I agree with your arguments, but you already know the answer. C# compiler cannot create expressions containing blocks, and all `Expression.Catch` methods are shortcuts for `Expression.MakeCatchBlock`, and the linked documentation states *"`type` must be non-null and match the type of variable (if it is supplied)."*. There are no other methods creating `CatchBlock` and `CatchBlock` has no public constructor. – Ivan Stoev Mar 31 '19 at 14:10
  • @ZevSpitz even though `try {...} catch {...}` is valid c# that doesn't mean you can create an expression like that, and since the CLR wraps any non-CLS exception in a `RunTimeWrapperException`, it's completely equivalent to `try {...} catch(Exception e) {...}` - so I don't really understand why do you insist on it. There's a perfectly valid alternative that you can use, so why not use it? – Zohar Peled Mar 31 '19 at 15:30
  • @ZoharPeled Please write the second line of your comment (_since the CLR wraps any non-CLS exception in a `RunTimeWrapperException`, it's completely equivalent to `try {...} catch(Exception e) {...}`_) as an answer, and I'll accept it. – Zev Spitz Apr 02 '19 at 23:26

1 Answers1

1

The usage of try {...} catch {...} to catch exceptions thrown from non .Net components and therefor don't inherit from System.Exception is misguided since the CLR automatically wraps such exceptions with a RuntimeWrappedException which obviously does inherit System.Exception - and therefor you can use try {...} catch(Exception e) {...} to catch thous exceptions as well.

Therefor, there is no need to handle the plain try {...} catch {...} separately from try {...} catch (Exception e) {...} since they both will catch all exceptions.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • _there really is no point of using `try {...} catch {...}`_ -- saving an extra variable declaration? But I was thinking the answer should be, since the two are equivalent, there is no need to handle the plain `try {...} catch {...}` separately from `try {...} catch (Exception e) {...}`. see [here](https://github.com/zspitz/ExpressionToString/blob/master/Shared/CSharpCodeWriter.cs#L535). – Zev Spitz Apr 03 '19 at 10:20
  • rephrased as requested. – Zohar Peled Apr 03 '19 at 10:57