Что CLR делает на броске? - PullRequest
       3

Что CLR делает на броске?

3 голосов
/ 20 августа 2010

Когда я работал над проектом, я подумал про себя: «Хм, было бы очень удобно зарегистрировать сообщение, а затем выдать исключение с тем же сообщением».Так как это позволило бы мне придерживаться принципа «исключения - для исключительных обстоятельств», но все же следить за тем, чтобы мы записывали подробную информацию о том, что пошло не так в системе.

Итак, что привело к:

public static class LogAndThrow
{
    public static void Message<TException>(string message) where TException : Exception
    {
        // Log message here

        var constructor = 
            typeof(TException).GetConstructor(new[] { typeof(string) });

        throw (TException)constructor.Invoke(new[] { message });
    }
}

Конечно, это немного грубо (и я сократил это для этого поста), но это работает.

Несмотря на то, что я являюсь типом людей, создающих исключения через отражение, я был раздражен, что трассировка стекабудет "испорчен" строкой LogAndThrow.Message ().

Поэтому я решил исправить это: -)

Мне удалось заменить трассировку стека некоторой сериализацией и другими хитростямиВсе очень глупо и грубо.Но я хотел выяснить это только потому, что.

Но я заметил кое-что любопытное:

var exception = new Exception();
throw exception;

После того, как это исключение создано, но до того, как оно выброшено, единственное, что устанавливается, - это Сообщение.,Трассировка стека и т. Д. Являются пустыми.

Вышесказанное эквивалентно следующему IL:

.locals init (
    [0] class [mscorlib]System.Exception exception)
nop 
newobj instance void [mscorlib]System.Exception::.ctor()
stloc.0 
ldloc.0 
throw 

Что мне кажется, что IL для 'throw' делает нечто большее, чем просто принятие этогоссылаться и подниматься по стеку.

Кто-нибудь знает, что делает среда выполнения с исключением в стеке, когда достигается IL 'throw'?

Трюк, который мы использовали ниже, чтобы изменитьстек относится к этой "магии" в броске, я думаю:

Этот код ужасен и неправильн.Больше научного эксперимента, чем что-либо, что когда-либо должно быть запущено в производство. Eververver EVER

var e = new Exception("message here");
try
{
     throw e;
}
finally
{
    // Get the private file _stackTraceString with reflection
    field.SetValue(e, new StackTrace(1).ToString());
}

1 Ответ

5 голосов
/ 20 августа 2010

Почему вы не можете изменить свой статический метод, чтобы он возвращал объект исключения и выбрасывал позже.Например,

// Do something
...
// Found error condition, need to throw an exception
if (error condition)
{
  throw LogAndThrow.Message("Message goes here");
}

Редактировать: AFAIK, нет способа изменить трассировку стека.Есть способы сохранить исходную трассировку стека при перезапуске исключений - см. Эту статью .

Другое правка :

Просто подумал, что яразместит дополнительную информацию и ссылки.По сути, CLR создает трассировку стека в объекте исключения только при возникновении исключения.Это было упомянуто в MSDN - цитата из MSDN:

Общеязыковая среда выполнения (CLR) обновляет трассировку стека всякий раз, когда в коде приложения выдается исключение (с помощью команды throwключевое слово).Если исключение было переброшено в методе, отличном от метода, в котором оно было изначально выброшено, трассировка стека содержит как местоположение в методе, где первоначально было выдано исключение, так и местоположение в методе, в котором было переброшено исключение.Если исключение выдается, а затем повторно вызывается в том же методе, трассировка стека содержит только местоположение, в которое было переброшено исключение, и не включает местоположение, в котором первоначально было выдано исключение

Этотакже упоминается здесь (где автор упоминает, что CLR будет выполнять обход стека, когда он обнаружит исключение в управляемом коде).

О некоторой связанной заметке (но немного не по теме) см. эту превосходную статью (с примером кода), где автор создает информацию трассировки альтернативного стека (в основном он ищет информацию отладки)из нестандартного места).

...