C# 经典实例 第二章 集合、枚举器和迭代器 #2.8 处理finally语句块和迭代器

问题:

你向迭代器中添加了一个try-finally语句块,并且注意到finally块并没有按所想的那样执行。

解决方案:

在GetEnumerator迭代器中用一个try块包围迭代代码,并在该try块后接一个finally块,代码如下所示:

     public static void TestFinallyAndIterators()
        {
            //Create a StringSet object and fill it with data
            StringSet strSet =
                new StringSet()
                    {"item1",
                        "item2",
                        "item3",
                        "item4",
                        "item5"};

            // Use the GetEnumerator iterator.
            foreach (string s in strSet)
                Console.WriteLine(s);
        }

运行这段代码时,将显示以下输出:

    item1 
    item2
    item3
    item4
    item5
    In iterator finally block

讨论:

你可能认为这段代码的输出将在显示strSet对象中的每个数据项之后显示 In iterator finally block字符串。不过,这不是在迭代器中处理finally块的方式。仅当迭代完成之后,代码执行离开foreach循环时(比如,当遇到break、return或throw块语句时),或者当执行yield break语句时,才会调用与迭代器成员体内包含yield返回语句的try块关联的所有finally块,从而有效地终止迭代器。

为了查看迭代器如何处理catch和finally语句块(注意,包含yield语句的try块内不能包含catch块),思考一下代码:


     public static void TestFinallyAndIterators()
        {
            //Create a StringSet object and fill it with data
            StringSet strSet =
                new StringSet()
                    {"item1",
                        "item2",
                        "item3",
                        "item4",
                        "item5"};

            // Display all data in StringSet object
            try
            {
                foreach (string s in strSet)
                {
                    try
                    {
                        Console.WriteLine(s);
                        // Force an exception here
                        //throw new Exception();
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("In foreach catch block");
                    }
                    finally
                    {
                        // Executed on each iteration
                        Console.WriteLine("In foreach finally block");
                    }
                }
            }
            catch (Exception)
            {
                Console.WriteLine("In outer catch block");
            }
            finally
            {
                // Executed on each iteration
                Console.WriteLine("In outer finally block");
            }

            /*
			This code is executed in this fashion when an exception occurs in the iterator:
			 - In iterator finally block
			 - In outer catch block
			 - In outer finally block

			This code is executed in this fashion when NO exception occurs in the iterator:
			 - item1
			 - In foreach finally block
			 - item2
			 - In foreach finally block
			 - item3
			 - In foreach finally block
			 - item4
			 - In foreach finally block
			 - item5
			 - In foreach finally block
			 - item6
			 - In foreach finally block
			 - In iterator finally block
			 - In outer finally block
        }
            

我们看到,每次迭代都会执行foreach循环内的finally语句块。不过,仅当所有迭代都完成后,才会执行迭代器内的finally语句块。另外,注意到迭代器的finally语句块将会包装foreach循环的finally语句块之前执行。

如果在处理第二个元素期间,迭代器自身发生异常,那么将会显示如下输出;

item1 In foreach finally block
    (Exception occurs here...)     
In foreach catch block 
In foreach finally block 
In iterator finally block 
In outer finally block

注意,在这种情况下,首先执行foreach循环内的catch和finally语句块,然后执行迭代器的finally语句块,最后执行外层finally语句块。

理解迭代器内的catch和finally语句块的工作方式将帮助你在正确的位置添加catch和finally语句块。如果需要在迭代完成之后立即执行一次finally语句块,可以将该finally语句块添加到迭代器方法中。不过,如果希望每次迭代都执行finally语句块,就需要将finally语句块置于foreach循环体内。

如果需要在迭代器异常发生之后立即捕获他们,就应该考虑将foreach循环包装在一个try-catch语句块中。foreach循环内的任何try-catch语句块都将错过从迭代器引发的异常。

参考:

MSDN文档中的“try-catch”“迭代器”“yield”“IEnumerator接口”和”IEnumerable接口”主题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值