异常陷阱
问题
请问您是否知道下面的代码有什么问题?
{
if (source == null)
{
throw new ArgumentNullException("source");
}
foreach (int item in source)
{
yield return item.ToString();
}
}
如果您没有看出来的话,不如运行一下这段代码:
static void Main(string[] args)
{
IEnumerable<string> values;
try
{
values = ToString(null);
}
catch (ArgumentNullException)
{
Console.WriteLine("Passed the null source");
return;
}
foreach (var s in values) { }
}
请问,运行上面的代码是否会抛出异常?从代码的意图上看,在ToString方法的一开始我们会检查参数是否为null,然后抛出异常——这本应被catch语句所捕获。但是事实上,代码直到foreach执行时才真正抛出了异常。这种“延迟”执行违反了我们的实现意图。为什么会这样呢?您可以使用.NET Reflector反编译一下,查看一下yield语句的等价C#实现是什么样的,一切就清楚了。
解决方案
对于这个问题,一般我们可以使用一对public和private方法配合来使用:
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return ToStringInternal(source);
}
private static IEnumerable<string> ToStringInternal(IEnumerable<int> source)
{
foreach (int item in source)
{
yield return item.ToString();
}
}
不妨再去查看一下现在的C#代码实现?
资源管理
问题
由于是延迟执行,一些原本最简单的代码模式可能就破坏了。例如:
static Func<string> ReadAllText(string file)
{
using (Stream stream = File.OpenRead(file))
{
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd;
}
}