2009-10-08 72 views
44

我已经编写了自己的自定义数据层以保存到特定文件,并且我使用自定义的DataContext模式对其进行了抽象。在using(){}块中产生return语句在执行之前进行处理

这都是基于.NET 2.0框架(给定了目标服务器的限制),所以即使其中一些看起来像LINQ-to-SQL,它不是!我刚刚实现了一个类似的数据模式。

请参阅下面的示例,了解我无法解释的情况的示例。

为了得到动物的所有实例 - 我做到这一点,它下面

public IEnumerable<Animal> GetAllAnimals() { 
     foreach (var animalName in AnimalXmlReader.GetNames()) 
     { 
      yield return GetAnimal(animalName); 
     } 
} 

的AnimalDataContext工作正常

public static IEnumerable<Animal> GetAllAnimals() { 
     AnimalDataContext dataContext = new AnimalDataContext(); 
      return dataContext.GetAllAnimals(); 
} 

而且GetAllAnimals的实现()方法在AnimalDataContext()( )实现了IDisposable,因为我在那里有一个XmlTextReader,我想确保它快速清理。现在

,如果我换第一次调用using语句里面,像这样

public static IEnumerable<Animal> GetAllAnimals() { 
     using(AnimalDataContext dataContext = new AnimalDataContext()) { 
      return dataContext.GetAllAnimals(); 
     } 
} 

,并在AnimalDataContext.GetAllAnimals的第一行把一个断点()方法和另一个突破点在第一线在AnimalDataContext.Dispose()方法,并执行...

的Dispose()方法首先被调用,这样AnimalXmlReader.GetNames()给出了“对象引用未设置为对象的实例”异常,因为AnimalXmlReader有已在Dispose()中设置为null ???

有什么建议吗?我有一种预感,它关系到收益率回报没有被允许一个try-catch块内被调用,这使用有效地表示,一旦编译...

+0

这基本上是我遇到的问题之一,看到我的问题在这里:http://stackoverflow.com/questions/1524367 – 2009-10-08 16:55:19

回答

50

当你调用GetAllAnimals它实际上并没有执行任何代码,直到你在foreach循环中枚举返回的IEnumerable。

在枚举IEnumerable之前,只要包装器方法返回,就立即抛弃dataContext。

最简单的解决办法是使包装方法的迭代器,以及像这样:

public static IEnumerable<Animal> GetAllAnimals() { 
    using (AnimalDataContext dataContext = new AnimalDataContext()) { 
     foreach (var animalName in dataContext.GetAllAnimals()) { 
      yield return GetAnimal(animalName); 
     } 
    } 
} 

这样一来,使用的语句会在外部迭代器进行编译,而且它只会被处置时外迭代器被处置。

另一种解决方案是枚举包装器中的IEnumerable。要做到这一点,最简单的方法是返回一个List<Animal>,像这样:

public static IEnumerable<Animal> GetAllAnimals() { 
    using (AnimalDataContext dataContext = new AnimalDataContext()) { 
     return new List<Animal>(dataContext.GetAllAnimals()); 
    } 
} 

注意,这个失去了延迟执行的好处,因此它会得到所有的动物,即使你不需要他们。

+1

谢谢SLaks - 第二个选项做到了这一招,它的整齐无损的代码行少了错误!该调用将进入位于WebForms项目的表示层中的“AnimalDataContextAdapter” - 专门用于枚举集合,因此延迟执行没有实际损失。 – 2009-10-08 17:10:42

+0

我会将其抽象为:从不接受使用'yield return'或其他推迟执行方法的方法中的IDisposable参数。 – 2011-04-19 13:20:01

+0

使用yield return是安全的,并在您的流[IFF](https:// www。 google.com/search?q=define%20iff)集合已完全枚举。 http://blogs.msdn.com/b/dancre/archive/2008/03/14/yield-and-usings-your-dispose-may-not-be-called.aspx – yzorg 2015-08-07 15:00:33

10

原因是GetAllAnimals方法不会返回动物的集合。它返回一个能够一次返回动物的枚举器。

当您从using块中的GetAllAnimals调用返回结果时,您只需返回枚举数。在方法退出之前,using块会处理数据上下文,并且在那一点上,枚举器根本没有读取任何动物。当您尝试使用枚举器时,它无法从数据上下文中获取任何动物。

解决方法是让GetAllAnimals方法也创建一个枚举器。这样,使用块将不会被关闭,直到你停止使用该枚举器:

public static IEnumerable<Animal> GetAllAnimals() { 
    using(AnimalDataContext dataContext = new AnimalDataContext()) { 
     foreach (Animal animal in dataContext.GetAllAnimals()) { 
     yield return animal; 
     } 
    } 
} 
相关问题