第十章(3)-异步调用中的异常与任务同步-学习笔记

同步编程中的异常处理由try和catch,同样异步编程时,异步调用的方法抛出一个异常时,CLR会捕捉他,当调用者线程(启动异步调用的线程)调用EndInvoke时,CLR会再次将异常抛出,这样调用者线程可捕获到她。如果BeginInvoke方法提供了一个回调方法,则CLR会在捕获异常后马上调用回调方法,并将异常传送给调用者线程。由此得出结论:

请在EndInvoke方法所在的代码处捕获异常(使用try和catch)。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace AsyncCalculateFolderSize5
{
    class Program
    {
        //计算指定文件夹的总容量
        private static long CalculateFolderSize(string FolderName)
        {
            if (Directory.Exists(FolderName) == false)
            {
                throw new DirectoryNotFoundException("文件夹不存在");
            }

            DirectoryInfo RootDir = new DirectoryInfo(FolderName);
            //获取所有的子文件夹
            DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
            //获取当前文件夹中的所有文件
            FileInfo[] files = RootDir.GetFiles();
            long totalSize = 0;
            //累加每个文件的大小
            foreach (FileInfo file in files)
            {
                totalSize += file.Length;
            }
            //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
            //这是通过递归调用实现的
            foreach (DirectoryInfo dir in ChildDirs)
            {
                totalSize += CalculateFolderSize(dir.FullName);
            }
            //返回文件夹的总容量
            return totalSize;
        }

        //定义一个委托
        public delegate long CalculateFolderSizeDelegate(string FolderName);

        private static CalculateFolderSizeDelegate d = new CalculateFolderSizeDelegate(CalculateFolderSize);

        //用于回调的函数
        public static void ShowFolderSize(IAsyncResult result)
        {
            try
            {
                long size = d.EndInvoke(result);
                Console.WriteLine("\n文件夹{0}的容量为:{1}字节\n", (String)result.AsyncState, size);

            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine("您输入的文件夹不存在");
            }

        }

        static void Main(string[] args)
        {
            string FolderName;

            while (true)
            {
                Console.WriteLine("请输入文件夹名称(例如:C:\\Windows),输入quit结束程序");
                FolderName = Console.ReadLine();
                if (FolderName == "quit")
                    break;
                d.BeginInvoke(FolderName, ShowFolderSize, FolderName);
            }

        }
    }
}
实现异步调用任务中的同步:

用一个例子说明这一概念其实很容易理解的。我们运行上面的代码,由于存在多个同时进行的异步调用,会出现下面的问题:

例如:用户输入文件夹名“C:\EBook”,然后,他想输入另一个文件夹名“C:\Mybook”,但是他刚输入到“C:\My”时前一项工作已完成控制台窗口输出“文件夹C:\EBook的容量为:770774156字节”,总之输入被打断,但是用户接着完成输入“book”,程序也是可以完成任务的。

但是用户不想有这种体验,这就涉及到“异步调用任务中的同步”。可以这样解决上面的问题:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace AsyncCalculateFolderSize6
{
    class Program
    {
          //计算指定文件夹的总容量
        private static long CalculateFolderSize(string FolderName)
        {
            if (Directory.Exists(FolderName) == false)
            {
                throw new DirectoryNotFoundException("文件夹不存在");
            }

            DirectoryInfo RootDir = new DirectoryInfo(FolderName);
            //获取所有的子文件夹
            DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
            //获取当前文件夹中的所有文件
            FileInfo[] files = RootDir.GetFiles();
            long totalSize = 0;
            //累加每个文件的大小
            foreach (FileInfo file in files)
            {
                totalSize += file.Length;
            }
            //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
            //这是通过递归调用实现的
            foreach (DirectoryInfo dir in ChildDirs)
            {
                totalSize += CalculateFolderSize(dir.FullName);
            }
            //返回文件夹的总容量
            return totalSize;
        }


        //定义一个委托
        public delegate long CalculateFolderSizeDelegate(string FolderName);

        private static CalculateFolderSizeDelegate d = new CalculateFolderSizeDelegate(CalculateFolderSize);


        //用于回调的函数
        public static void ShowFolderSize(IAsyncResult result)
        {
            try
            {
                long size = d.EndInvoke(result);
                while (Console.CursorLeft != 0)
                {
                    //等待2秒
                    System.Threading.Thread.Sleep(2000);
                }
                Console.WriteLine("\n文件夹{0}的容量为:{1}字节\n", (String)result.AsyncState, size);

            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine("您输入的文件夹不存在");
            }

        }
        static void Main(string[] args)
        {
            string FolderName;

            while (true)
            {
                Console.WriteLine("请输入文件夹名称(例如:C:\\Windows),输入quit结束程序");
                FolderName = Console.ReadLine();
                if (FolderName == "quit")
                    break;
                d.BeginInvoke(FolderName, ShowFolderSize, FolderName);
            }

        }
    }
}
控制台窗口的坐标是以字符为单位的,当用户输入时,光标X轴方向的坐标会不断增大,由此判断用户是否在输入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值