MST
星途 面试题库

面试题:C#异步编程中的异常处理与资源管理

假设你有一个复杂的异步操作链,其中包含多个使用async/await的方法调用,并且每个方法可能会抛出不同类型的异常。请详细说明如何在这种情况下进行全面且合理的异常处理?同时,如何确保在异步操作过程中资源(如文件句柄、数据库连接等)能够正确地释放和管理?
30.0万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

异常处理

  1. 全局try - catch块:在最外层的异步函数中使用try - catch块,捕获整个异步操作链中的异常。这样可以确保任何一个async/await方法抛出的异常都能被捕获。
async function complexAsyncOperation() {
    try {
        await method1();
        await method2();
        await method3();
    } catch (error) {
        // 处理所有异常
        console.error('捕获到异常:', error);
    }
}
  1. 细化异常类型处理:根据不同的异常类型进行不同的处理。可以使用instanceof来判断异常类型。
async function complexAsyncOperation() {
    try {
        await method1();
        await method2();
        await method3();
    } catch (error) {
        if (error instanceof SpecificErrorType1) {
            // 处理SpecificErrorType1类型的异常
            console.error('处理SpecificErrorType1异常:', error);
        } else if (error instanceof SpecificErrorType2) {
            // 处理SpecificErrorType2类型的异常
            console.error('处理SpecificErrorType2异常:', error);
        } else {
            // 处理其他未知类型的异常
            console.error('捕获到未知异常:', error);
        }
    }
}
  1. 局部try - catch块:在每个async/await方法调用处也可以添加局部try - catch块,这样可以对单个方法的异常进行更细粒度的处理,同时不影响整个操作链的继续执行(如果有需要的话)。
async function complexAsyncOperation() {
    try {
        await method1();
    } catch (error) {
        // 处理method1抛出的异常
        console.error('method1异常:', error);
    }
    try {
        await method2();
    } catch (error) {
        // 处理method2抛出的异常
        console.error('method2异常:', error);
    }
    try {
        await method3();
    } catch (error) {
        // 处理method3抛出的异常
        console.error('method3异常:', error);
    }
}

资源释放和管理

  1. 使用try - finally块:对于需要释放的资源(如文件句柄、数据库连接等),在获取资源后,使用try - finally块确保无论操作是否成功,资源都能被正确释放。
async function readFileAsync() {
    let fileHandle;
    try {
        fileHandle = await openFile(); // 假设这是打开文件的异步操作
        const data = await readFromFile(fileHandle); // 假设这是从文件读取数据的异步操作
        return data;
    } catch (error) {
        console.error('读取文件时出错:', error);
    } finally {
        if (fileHandle) {
            await closeFile(fileHandle); // 假设这是关闭文件的异步操作
        }
    }
}
  1. 使用using语句(某些语言支持,如C#):在C#中,可以使用using语句来自动管理实现了IDisposable接口的资源。
using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        try
        {
            using (StreamReader reader = new StreamReader("example.txt"))
            {
                string content = await reader.ReadToEndAsync();
                Console.WriteLine(content);
            }
        }
        catch (IOException e)
        {
            Console.WriteLine($"读取文件时出错: {e.Message}");
        }
    }
}
  1. 数据库连接管理:对于数据库连接,可以使用连接池技术,并在操作完成后及时释放连接回连接池。在使用async/await时,确保连接的获取和释放操作都是异步的。
const { Pool } = require('pg');

const pool = new Pool({
    user: 'user',
    host: 'host',
    database: 'database',
    password: 'password',
    port: 5432,
});

async function queryDatabase() {
    let client;
    try {
        client = await pool.connect();
        const result = await client.query('SELECT * FROM some_table');
        return result.rows;
    } catch (error) {
        console.error('数据库查询出错:', error);
    } finally {
        if (client) {
            client.release();
        }
    }
}