12

I'm generating wrappers for types by using System.Reflection.Emit. At one point it's possible that the original object is throwing a error on access ( FaultException ) and the error should be catched by my try { } catch (Exception e) { } which i have implemented, but it does not.

The code is shown correcly by ILSpy.

try
{
    if (original.Station != null)
    {
        if (objectDictionary.ContainsKey(original.Station))
        {
            this.Station = (objectDictionary[original.Station] as StationWrapper);
        }
        else
        {
            this.Station = new StationWrapper(original.Station, objectDictionary);
        }
    }
}
catch (Exception arg_6D_0)
{
    ReportManager.Log(arg_6D_0);
}

Code generation

This is the code for the assembly-generation.

Label ex = il.BeginExceptionBlock();
....
// Exception block end
il.Emit(OpCodes.Leave, ex);
il.BeginCatchBlock(typeof(Exception));
il.Emit(OpCodes.Call, ReportManager_Log);
il.EndExceptionBlock();

Edit

The exception is getting caught by user code but not by IL-Code.

Disassembly

Removed some namespaces of the customer here. The write line has been added the last minutes.

.try
{
    IL_0019: ldarg.1
    IL_001a: call instance class [...]...Station [...]...StationBase::get_Station()
    IL_001f: brfalse IL_0063

    IL_0024: ldarg.2
    IL_0025: ldarg.1
    IL_0026: call instance class [...]...Station [...]...StationBase::get_Station()
    IL_002b: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<object, object>::ContainsKey(!0)
    IL_0030: brfalse IL_0051

    IL_0035: ldarg.0
    IL_0036: ldarg.2
    IL_0037: ldarg.1
    IL_0038: call instance class [...]...Station [...]...StationBase::get_Station()
    IL_003d: call instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<object, object>::get_Item(!0)
    IL_0042: isinst ...StationWrapper
    IL_0047: call instance void ...StationBaseWrapper::set_Station(class ...StationWrapper)
    IL_004c: br IL_0063

    IL_0051: ldarg.0
    IL_0052: ldarg.1
    IL_0053: call instance class [...]...Station [...]...StationBase::get_Station()
    IL_0058: ldarg.2
    IL_0059: newobj instance void ....StationWrapper::.ctor(class [...]...Station, class [mscorlib]System.Collections.Generic.Dictionary`2<object, object>)
    IL_005e: call instance void ...StationBaseWrapper::set_Station(class ...StationWrapper)

    IL_0063: leave IL_007c
} // end .try
catch [mscorlib]System.Exception
{
    IL_0068: ldstr "Its comming home"
    IL_006d: call void [mscorlib]System.Console::WriteLine(string)
    IL_0072: call void [...Report]...ReportManager::Log(class [mscorlib]System.Exception)
    IL_0077: leave IL_007c
} // end handler

Edit 2

When throwing a System.Exception in IL code, before the FaultException'1 can occur, the exception is getting handled. Tested with Exception and ArgumentException.

casperOne
  • 73,706
  • 19
  • 184
  • 253
Felix K.
  • 6,201
  • 2
  • 38
  • 71
  • For info, I've tested my sample with FaultException and it still works fine; frankly, I'm not sure there is much we can do until you can help provide a failing example. The only example I have (that indeed: uses your code) works perfectly. So: what is different about your real scenario that isn't coming over in the question? – Marc Gravell Feb 29 '12 at 07:18
  • @MarcGravell Found out that this seems to be a VS2010 bug, the exception is shown as uncaught but is getting caught by the exception block when continue the application( Didn't noticed this because i have a uncaught-exception-handler ). Not sure why this happens, its a external dll and even exceptions in VS are disabled. Other exceptions are not shown. – Felix K. Feb 29 '12 at 12:57

2 Answers2

7

All works fine here; are you sure it isn't a nested exception block?

Example:

using System;
using System.Reflection.Emit;

public class Test
{
    static void Main()
    {
        var dm = new DynamicMethod("foo", null, new[] {typeof(bool)});
        var il = dm.GetILGenerator();

        Label ex = il.BeginExceptionBlock();
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, typeof(Test).GetMethod("Throw"), null);
        il.Emit(OpCodes.Leave, ex);

        il.BeginCatchBlock(typeof(Exception));
        il.EmitCall(OpCodes.Call, typeof(Test).GetMethod("Log"), null);
        il.EndExceptionBlock();
        il.Emit(OpCodes.Ldstr, "done");
        il.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
                      new[] {typeof(string)}), null);

        il.Emit(OpCodes.Ret);
        var act = (Action<bool>)dm.CreateDelegate(typeof (Action<bool>));
        Console.WriteLine("Expect success:");
        act(false);
        Console.WriteLine("Expect fail:");
        act(true);
        Console.WriteLine("(all done)");
    }
    public static void Throw(bool fatal)
    {
        if(fatal) throw new InvalidOperationException("Boom!");
    }
    public static void Log(Exception ex)
    {
        Console.WriteLine("Error: " + ex.Message);
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Absolutly, i reproduced the same error with another wrapper. The call stack points to the `get_Station`-method of the `Station`-property and this access is within the `try-catch` block. The `FaultException'1`exception is going through. – Felix K. Feb 21 '12 at 10:13
  • 3
    @Felix the difficulty is: I've produced a working sample using all the IL from your question; anything else would be pure invention on my part, and not helpful. I suggest you take the working version (above) and adapt it bit-by-bit until you reproduce the problem. Then you'll know where to look. – Marc Gravell Feb 21 '12 at 10:16
  • @FelixK I am of course assuming that `ReportManager_Log` is actually a method-info? – Marc Gravell Feb 21 '12 at 10:17
  • Yes i'am, the exception got caught by user code. But not by my code. So its the old issue. – Felix K. Feb 21 '12 at 10:30
  • @FelixK any chance it is C++ throwing something that isn't actually an Exception, and you the automatic wrapping disabled? – Marc Gravell Feb 21 '12 at 10:30
  • Ignore my old comment, it can be caught with a try-catch block but is not working in il-code. – Felix K. Feb 21 '12 at 10:31
  • Noticed that the exceptions `Exception` and `ArgumentException` is getting caught correctly when throwing them before the `FaultException'1` occurs. – Felix K. Feb 21 '12 at 10:57
0

This is actually seems to be a Visual-Studio 2010 bug. All exceptions are ignored in VS when catched, but VS shows the exception anyway.

Not all exceptions are ignored, this seems to depend on the code which throws the exception. Generated exceptions ( via Emit ) are ignored, exceptions which are from a outside DLL are not ignored.

Felix K.
  • 6,201
  • 2
  • 38
  • 71