Pytanie Ilogenerator wychwytywania wyjątków nie działa


Generuję wrappery dla typów za pomocą System.Reflection.Emit. W pewnym momencie możliwe jest, że oryginalny obiekt rzuca błąd dostępu ( FaultException ) i błąd powinien zostać przechwycony przez mój try { } catch (Exception e) { } które zaimplementowałem, ale tak nie jest.

Kod jest wyświetlany poprawnie przez 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);
}

Generowanie kodu

To jest kod dla generowania zespołu.

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

Edytować

Wyjątkiem jest złapanie przez kod użytkownika, ale nie przez kod IL-Code.

Demontaż

Tutaj usunięto niektóre przestrzenie nazw klienta. Linia zapisu została dodana do ostatnich minut.

.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

Edytuj 2

Podczas rzucania System.Exception w kodzie IL, przed FaultException'1 może wystąpić, wyjątek jest przetwarzany. Przetestowano za pomocą Exception i ArgumentException.


12
2018-02-21 09:41


pochodzenie


Dla informacji, przetestowałem moją próbkę z FaultException i nadal działa dobrze; Szczerze mówiąc, nie jestem pewien, czy możemy zrobić wiele, dopóki nie pomożemy dostarczyć przykładu zepsutego. Jedyny przykład jaki mam (który faktycznie: używa twojego kodu) działa idealnie. A więc: co jest innego w prawdziwym scenariuszu, który nie pojawia się w pytaniu? - Marc Gravell♦
@MarcGravell Okazało się, że jest to błąd VS2010, wyjątek jest wyświetlany jako nieprzechwycony, ale zostaje zatrzymany przez blok wyjątków, gdy kontynuuje aplikację (nie zauważyłem tego, ponieważ mam program obsługi uncaught-exception). Nie wiem, dlaczego tak się dzieje, jego zewnętrzna biblioteka dll, a nawet wyjątki w VS są wyłączone. Inne wyjątki nie są wyświetlane. - Felix K.


Odpowiedzi:


Wszystko działa dobrze tutaj; jesteś pewien, że nie jest to zagnieżdżony blok wyjątków?

Przykład:

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);
    }
}

6
2018-02-21 10:01



Absolutnie, powtórzyłem ten sam błąd w innym opakowaniu. Stos wywołań wskazuje na get_Station- metoda Station-property i ten dostęp jest w try-catch blok. The FaultException'1wyjątek przechodzi. - Felix K.
@Fix the diffure to: Stworzyłem próbną próbkę, używając wszystkich IL z twojego pytania; wszystko inne byłoby czystym wynalazkiem z mojej strony, a nie pomocne. Sugeruję, abyś wziął działającą wersję (powyżej) i dostosował ją bit po bicie aż do odtworzenia problemu. Wtedy będziesz wiedział, gdzie szukać. - Marc Gravell♦
@FelixK Oczywiście zakładam, że ReportManager_Log jest właściwie metodą-informacją? - Marc Gravell♦
Tak, jestem, wyjątek został złapany przez kod użytkownika. Ale nie według mojego kodu. Tak więc jest to stary problem. - Felix K.
@FelixK jest szansa, że ​​to C ++ rzuca coś, co nie jest w rzeczywistości wyjątkiem, a ty automatyczne owijanie jest wyłączone? - Marc Gravell♦


Wygląda na to, że jest to błąd Visual-Studio 2010. Wszystkie wyjątki są ignorowane w VS podczas catched, ale VS pokazuje mimo to wyjątek.

Nie wszystkie wyjątki są ignorowane, wydaje się to zależeć od kodu, który zgłasza wyjątek. Wygenerowane wyjątki (poprzez Emit) są ignorowane, wyjątki pochodzące z zewnętrznej biblioteki DLL nie są ignorowane.


0
2018-05-10 10:07