1

我正在编写一个库(作为 Nuget 包分发),它允许用户将多个“阅读器”配置到存储库。它通过每个阅读器并通过第一个可用阅读器访问存储库。

读者具有可用性状态,不可用也不例外。但是,还有一些其他异常情况需要通知调用应用程序。通知后,程序应该能够尝试使用下一个阅读器。

这些是我考虑过的选项

  • 抛出异常:这里的问题是控制流返回
  • 累积状态并返回:读者有其他东西要返回,我不希望将状态与它捆绑在一起
  • 像这样抛出异常:看起来很可怕 :) 就像它可能会创建孤立线程或内存泄漏
  • 事件:我不知道如何通过事件来做到这一点
4

2 回答 2

3

这是一个协调器的示例,它将返回结果和处理期间发生的任何异常。

public class Coordinator<T> where T: new()
{
    public async Task<Tuple<IEnumerable<T>, AggregateException>> GetResultsAsync()
    {
        var tasks = new Task<T>[10];
        for(int i = 0; i < 10; i++)
        {
            tasks[i] = Task.Run(() => GetResult(i));
        }

        var results = new List<T>();
        var exceptions = new List<Exception>();

        foreach(var item in tasks)
        {
            try
            {
                var result = await item;
                results.Add(result);
            }
            catch(Exception e)
            {
                exceptions.Add(e);
            }
        }

        return Tuple.Create<IEnumerable<T>, AggregateException>(results, new AggregateException(exceptions));
    }

    private T GetResult(int i)
    {
        if (i % 2 == 0) throw new Exception("Result cannot be even.");
        return new T();
    }
}
于 2013-06-25T11:29:46.600 回答
2

由于应用程序应该继续运行,因此在调用者眼中这些都不是例外。异常应该总是中止。

我会在内部做类似 .NET 的事情并举办一个活动。

public class ReaderFailedEventArgs : EventArgs
{
    public ReaderFailedEventArgs (IReader reader, Exception failure)
    {
    }

    // [.. Two read only properties here ..]
}

public class Worker
{
    public event EventHandler<ReaderFailedEventArgs> ReaderFailed = delegate{};

    public IEnumerable<Data> Process()
    {
        foreach (var reader in _readers)
        {
            try
            {
                return reader.Read();
            }
            catch (Exception ex)
            {
                ReaderFailed(this, new ReaderFailedEventArgs(reader, ex);
            }
        }

        // now, this is a real exception since user expects to get data
        throw new InvalidOperationException("All readers failed");
    }
}

使用空委托 ( delegate{}) 分配事件允许我们使用事件而无需检查它是否为空(它也使事件线程安全)。

于 2013-06-27T06:02:00.937 回答