您的位置:首页 > 其它

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

2016-01-05 10:29 387 查看
同步编程中的异常处理由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轴方向的坐标会不断增大,由此判断用户是否在输入。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: