gpt4 book ai didi

c# - 在迭代器的 finally block 中获取对异常的引用

转载 作者:太空狗 更新时间:2023-10-29 18:04:14 26 4
gpt4 key购买 nike

有没有办法在 iterator function or property that allow try..finally but not try..catch 的 finally block 中获取对异常的引用? ?

我不会用它来改变或扰乱控制流,但无论如何都希望能够在 finally block 中获得对异常的引用(如果抛出的话),以便从它并可能向 Data member 添加内容.

我明白,由于编译器从迭代器生成类的性质,可能/不允许出于同样的原因,为什么 try..catch 绕过 yield 语句首先是不允许的。但我仍然希望可能有某种方法(甚至是丑陋的技巧)来获取异常。

简化示例:

IEnumerable<SomeClass> Something
get
{
try
{
throw new SomeException();
yield return new SomeClass();
}
finally
{
Exception ex = ... // <= TODO - get hold of the exception here [if one was thrown]...
}
}

最佳答案

这是一个非常有趣的问题。

回想一下,在 Linq 中,提供了许多有效链接在一起的标准运算符。目前没有一种方法可以让您围绕内部序列包装自定义异常处理。

所以我的建议是编写一个新的,允许您指定一个操作来处​​理 IEnumerator.MoveNext 执行期间发生的任何异常:

public static class EnumerableExceptions
{
public static IEnumerable<TItem> Catch<TItem, TEx>(
this IEnumerable<TItem> source,
Action<TEx> handler) where TEx : Exception
{
using (var enumerator = source.GetEnumerator())
{
for (; ; )
{
try
{
if (!enumerator.MoveNext())
yield break;
}
catch (TEx x)
{
handler(x);
yield break;
}

yield return enumerator.Current;
}
}
}
}

现在假设我们有这个:

public class NastyException : Exception { }

public static IEnumerable<String> StringYielder()
{
yield return "apple";
yield return "banana";

throw new NastyException();

yield return "oracle";
yield return "grapefruit";
yield return "microsoft";
}

我们希望能够将所有主体包裹在 try/catch 中,这很遗憾是非法的。但是我们可以做的是包装生成的序列:

public static IEnumerable<String> LoggingStringYielder()
{
return StringYielder().Catch(
(NastyException ex) =>
Console.WriteLine("Exception caught: " + ex.StackTrace));
}

也就是说,我通过调用“原始”StringYielder 方法获得一个序列,然后我将新的 Catch 运算符应用于它,指定如果发生某种异常类型。在这里,我将打印堆栈跟踪。

如果我这样做:

foreach (var str in LoggingStringYielder())
Console.WriteLine(str);

程序在没有崩溃的情况下完成,输出为:

apple
banana
Exception caught: at ConsoleApplication7.Program.<StringYielder>.. blah

因此,虽然您不能在原始迭代器方法内的代码周围放置 try catch,但您现在可以将其“包装”在该迭代器方法的外部。这就像在每个 yield return 之间 代码周围注入(inject)异常处理的非侵入式方式。

奖励更新!

对我最后一句话的措辞方式非常挑剔:

  • 首先,您可以在第一个 yield return 之前抛出异常,它的处理方式相同,因为该代码在第一次调用 MoveNext 时执行。所以“...代码之前每个...”会比“...代码之间每个...”更准确。

  • 其次,yield return 可能会接受必须求值的表达式,并且可能会在求值期间抛出异常。这应该被视为在 yield return 发生之前执行的代码,即使从句法上讲它出现在它之后。

关于c# - 在迭代器的 finally block 中获取对异常的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4710897/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com