技术开发 频道

.NET中*延迟*特性的几个陷阱

 异常陷阱

 问题

 请问您是否知道下面的代码有什么问题?

public static IEnumerable<string> ToString(IEnumerable<int> source)

 {

 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方法配合来使用:

public static IEnumerable<string> ToString(IEnumerable<int> source)

 {

 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;

 }

 }

 

0
相关文章