是否可以使用IL从* calling *方法返回?

时间:2014-09-12 10:08:34

标签: asp.net .net vb.net il

Response.Redirect的工作方式有一个恼人的怪癖:你几乎总是希望立即终止执行并跳转到新页面:

If ThisIsTheWrongPage Then
    Response.Redirect(sUrl, False)
End If

'this code should not execute
DoSomethingWithThisPage

但是Response.Redirect并没有结束执行,它只是继续前进并执行后续的代码行。这对我正在维护的遗留应用程序造成了很大的破坏。所以你必须这样做:

If ThisIsTheWrongPage Then
    Response.Redirect(sUrl, False)
    Return
End If

我想要做的是实现这样的方法:

Sub RedirectToUrl(sUrl As String)
  'redirect to the specified url
  HttpContext.Current.Response.Redirect(sUrl, False)

  'return from the CALLING method
End Sub

然后我可以写下这个:

If ThisIsTheWrongPage Then
    RedirectToUrl(sUrl)
End If

不必担心丢失的Return语句。我知道编写返回语句并不难,但代码中大约有1000个,并且添加了新的语句,我想要一个开发人员可以调用的方法,而不必小心它{{1}声明。这是一个等待发生的错误。

我知道在传统的.NET代码中没有办法做到这一点,但我想知道它是否可以在IL中实现,弹出堆栈两次并跳转到调用方法的返回位置。

3 个答案:

答案 0 :(得分:2)

方法可以更改调用它的方法的返回点的唯一方法是抛出异常。考虑到使用异常处理程序编写许多Web应用程序以防止页面向用户返回500个错误的方式,可能很难通过抛出异常来提供所需的行为。

指示调用者返回的一个问题是无法指定该方法的返回值。异常通过将异常本身传播到堆栈直到找到处理程序来解决此问题。

答案 1 :(得分:2)

这是不可能的。你打破了调用方法的不变量。当你打电话给你没有写过的方法时会发生什么事情是不可预测的。

Redirect有一个参数可以设置为使其在当前线程上抛出ThreadAbortException。这完全是针对您的用例。它有效地中止了页面的执行。

答案 2 :(得分:1)

看看这个,它使用jmp opcode, 也许这符合你的需求。

.assembly JumpTest{}
.module JumpTest.exe
.namespace Test{
.class public auto ansi JumpClass extends [mscorlib]System.Object {
    .method public static void Main() cil managed{
        .entrypoint 
        .maxstack 8

        ldstr "start"
        call void [mscorlib]System.Console::WriteLine(string)
        ldstr ""
        call void Test.JumpClass::Page(string)
        ldstr "end"
        call void [mscorlib]System.Console::WriteLine(string)
        ret
    }

    .method public static void Page(string sUrl) cil managed{
        ldc.i4.1 //always redirect in this test
        brfalse.s target

        jmp void Test.JumpClass::RedirectToUrl(string)

        target:
        ldstr "Page() stuff here"
        call void [mscorlib]System.Console::WriteLine(string)
        ret
    }

    .method public static void RedirectToUrl(string sUrl) cil managed{
        ldstr "RedirectToUrl() stuff here"
        call void [mscorlib]System.Console::WriteLine(string)
        ret
    }
}}