52

我编写了自己的自定义数据层以持久保存到特定文件,并使用自定义 DataContext 模式对其进行了抽象。

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

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

要获取所有实例Animal- 我这样做并且效果很好

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

以及下面GetAllAnimals()方法的实现AnimalDataContext

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

AnimalDataContext工具,IDisposable因为我有一个XmlTextReader在那里,我想确保它得到迅速清理。

现在,如果我像这样将第一个调用包装在 using 语句中

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

并在方法的第一行放置一个断点,在AnimalDataContext.GetAllAnimals()方法的第一行放置另一个断点AnimalDataContext.Dispose(),然后执行...

Dispose()方法被称为 FIRST 以便AnimalXmlReader.GetNames()给出“对象引用未设置为对象实例”异常,因为AnimalXmlReader已设置nullDispose()???

有任何想法吗?我有一种预感,它与yield return不允许在 try-catch 块内被调用有关,该块using有效地表示,一旦编译......

4

2 回答 2

60

当您调用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);
        }
    }
}

这样,using语句会在外层迭代器中编译,只有在外层迭代器被释放时才会被释放。

另一种解决方案是枚举包装器中的 IEnumerable。最简单的方法是返回 a List<Animal>,如下所示:

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

请注意,这失去了延迟执行的好处,因此即使您不需要它们,它也会获得所有动物。

于 2009-10-08T17:04:49.700 回答
12

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

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

一种解决方法是让 GetAllAnimals 方法也创建一个枚举器。这样,在您停止使用该枚举器之前,不会关闭 using 块:

public static IEnumerable<Animal> GetAllAnimals() {
   using(AnimalDataContext dataContext = new AnimalDataContext()) {
      foreach (Animal animal in dataContext.GetAllAnimals()) {
         yield return animal;
      }
   }
}
于 2009-10-08T17:05:42.867 回答