我遇到了一个非常奇怪的问题。以下代码无法运行。
static IEnumerable<int> YieldFun()
{
int[] numbers = new int[3] { 1, 2, 3 };
if(numbers.Count()==3)
throw new Exception("Test...");
//This code continues even an exception was thrown above.
foreach(int i in numbers)
{
if(i%2==1)
yield return numbers[i];
}
}
static void Main(string[] args)
{
IEnumerable<int> result = null;
try
{
result = YieldFun();
}
catch (System.Exception ex) //Cannot catch the exception
{
Console.WriteLine(ex.Message);
}
foreach (int i in result)
{
Console.Write(" " + i);
}
}
两个问题。
首先,即使抛出异常,YieldFun似乎仍然可以继续工作。
其次,调用者的try-catch块无法捕获抛出的异常。
为什么这样?以及如何解决这个问题?
答案 0 :(得分:6)
这是由迭代器的延迟执行引起的。您的异常比您想象的要晚一些:foreach (int i in result)
尝试迭代并抛出,但是您不会在那里捕获异常。
在尝试迭代项目之前,不会执行函数体。所以只是调用这个函数实际上并没有达到“throw ...”语句。您可以手动迭代结果以查看抛出异常的确切位置。
答案 1 :(得分:3)
您可以这样做来分离延迟部分(包含yield
的范围导致构建迭代器)....并在分配发生时执行检查。
static IEnumerable<int> YieldFun()
{
int[] numbers = new int[3] { 1, 2, 3 };
if (numbers.Count() == 3)
throw new Exception("Test...");
return YieldFunImpl(numbers);
}
static IEnumerable<int> YieldFunImpl(int []numbers)
{
//This code continues even an exception was thrown above.
foreach (int i in numbers)
{
if (i % 2 == 1)
yield return numbers[i];
}
}
static void Main(string[] args)
{
IEnumerable<int> result = null;
try
{
result = YieldFun();
}
catch (System.Exception ex) //Cannot catch the exception
{
Console.WriteLine(ex.Message);
}
if (result != null)
{
foreach (int i in result)
{
Console.Write(" " + i);
}
}
}
}
当异常消失时(因为你的Count()== 3)....你的捕获将被调用,你的result
将不被设置....所以当for循环试图迭代结果......它将是null
....你需要添加一个空检查。