亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 try 塊中返回的偽代碼是什么?

在 try 塊中返回的偽代碼是什么?

C#
慕森王 2023-12-17 10:03:52
下面的代碼class Animal : IDisposable{    static string Invoker()    {        using (Animal a = new Animal())        {            return a.Greeting();        }    }    public void Dispose()    {        Console.WriteLine("Disposed");    }    public string Greeting()    {        return "Hello World";    }    static void Main()    {        Console.WriteLine("Before");        Console.WriteLine(Invoker());        Console.WriteLine("After");    }}產生BeforeDisposedHello WorldAfter因為這個輸出中 Disposed 出現在 Hello World 之前,我猜using (Animal a = new Animal()){    return a.Greeting();}相當于Animal a = new Animal();string buffer = null;try{    buffer = a.Greeting();}finally{    a.Dispose();    return buffer;}但是,它顯然不正確,因為出現以下錯誤消息:控制不能離開finally塊的主體。那么我最終的猜測就變成了如下。Animal a = new Animal();string buffer = null;try{    buffer = a.Greeting();    return buffer;}finally{    a.Dispose();    //return buffer;}但是,我仍然很困惑,如果 在執行順序中排在第一位,如何調用 Dispose() 。 提前離開函數體使得 必須由某些東西(其他代理或線程或垃圾收集器或我不詳細了解的任何隱藏機制)調用。這是我的想象。 另外,如果 首先出現,那么輸出應該是return bufferDispose()return bufferBeforeHello WorldDisposedAfter問題你能告訴我編譯器或內部機制如何調用Dispose() while return buffer 首先出現,導致過早離開函數體Invoker?
查看完整描述

2 回答

?
茅侃侃

TA貢獻1842條經驗 獲得超21個贊

語言規范?指出這種形式的 using 語句:


using (ResourceType resource = expression) statement

相當于:


{

? ? ResourceType resource = expression;

? ? try {

? ? ? ? statement;

? ? }

? ? finally {

? ? ? ? ((IDisposable)resource).Dispose();

? ? }

}

因此,您的 using 語句相當于:


{

? ? Animal a = new Animal();

? ? try {

? ? ? ? return a.Greeting();

? ? } finally {

? ? ? ? a.Dispose();

? ? }

}

我只能猜測為什么你認為這是違反直覺的。也許是因為您認為由于?而無法到達?finally?那么,規范還指定:return

finally?塊中的語句總是在控制時執行 留下?try?語句。無論控制權轉移是否如此 發生作為正常執行的結果,作為執行的結果?break、continue、goto?或?return?語句,或作為以下結果 從?try?語句中傳播異常。


查看完整回答
反對 回復 2023-12-17
?
臨摹微笑

TA貢獻1982條經驗 獲得超2個贊

該字符串在處理后返回,然后寫入控制臺。


該字符串在方法結束時返回,即在 dispose 之后返回。


“返回”是指“返回”。函數完成所有操作后返回一個變量。


這就好比一個 goto 是通過所有的finally塊到達方法的末尾,然后只在這里返回值。


在您的情況下,您的代碼相當于:


static string Invoker()

{

    string result;

    using (Animal a = new Animal())

    {

        result = a.Greeting();

        goto end;

        // a return here is like a "goto end"

        // done after invoking the Dispose()

        // while exiting the using block

    }

    // others things possible here

    // return anything_else_here;

    end:

      return result;

}

下面是 VS2017 生成的 IL 代碼(使用 .NET Reflector):


.method private hidebysig static string Invoker() cil managed

{

    .maxstack 1

    .locals init (

        [0] class ConsoleApp1.Animal a,

        [1] string str)

    L_0000: nop 

    L_0001: newobj instance void ConsoleApp1.Animal::.ctor()

    L_0006: stloc.0 

    L_0007: nop 

    L_0008: ldloc.0 

    L_0009: callvirt instance string ConsoleApp1.Animal::Greeting()

    L_000e: stloc.1 

    L_000f: leave.s L_001c

    L_0011: ldloc.0 

    L_0012: brfalse.s L_001b

    L_0014: ldloc.0 

    L_0015: callvirt instance void [mscorlib]System.IDisposable::Dispose()

    L_001a: nop 

    L_001b: endfinally 

    L_001c: ldloc.1 

    L_001d: ret 

    .try L_0007 to L_0011 finally handler L_0011 to L_001c

}

如您所見,ret 位于調用 dispose 之后的末尾。


具體來說,代碼將字符串壓入堆棧,并在返回到調用方法后將其彈出堆棧以檢索字符串。


在此示例中,控制臺寫入兩次內容并等待按鍵,然后退出該方法:


static string Test()

{

  try

  {

    try

    {

      return "a string"; // the string is pushed in the stack here

    }

    finally

    {

      Console.WriteLine("1");

      Console.ReadKey();

      // no other return allowed here

    }

  }

  finally

  {

    Console.WriteLine("2");

    Console.ReadKey();

    // no other return allowed here

  }

}


// The method that calls Test() next pop the stack to retreive the string

這與在該塊末尾調用 Dispose 的 using 塊發生的情況相同,而要返回的值位于等待調用者彈出的堆棧中。


goto的解釋是一個晦澀的解釋,如果你了解IL的話你可能會忘記它,但它可以幫助你理解。


查看完整回答
反對 回復 2023-12-17
  • 2 回答
  • 0 關注
  • 182 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號