Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# using(){}块中的yield return语句在执行之前进行处理_C#_.net 2.0_Idisposable_Using_Yield Return - Fatal编程技术网

C# using(){}块中的yield return语句在执行之前进行处理

C# using(){}块中的yield return语句在执行之前进行处理,c#,.net-2.0,idisposable,using,yield-return,C#,.net 2.0,Idisposable,Using,Yield Return,我已经编写了自己的自定义数据层来持久化到特定的文件,并使用自定义DataContext模式对其进行了抽象 这一切都是基于.NET2.0框架的(给定目标服务器的约束),因此,尽管其中一些可能看起来像LINQtoSQL,但事实并非如此!我刚刚实现了一个类似的数据模式 请参见下面的示例,以了解我无法解释的情况 要获取动物的所有实例-我这样做,效果很好 public static IEnumerable<Animal> GetAllAnimals() { AnimalData

我已经编写了自己的自定义数据层来持久化到特定的文件,并使用自定义DataContext模式对其进行了抽象

这一切都是基于.NET2.0框架的(给定目标服务器的约束),因此,尽管其中一些可能看起来像LINQtoSQL,但事实并非如此!我刚刚实现了一个类似的数据模式

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

要获取
动物的所有实例
-我这样做,效果很好

public static IEnumerable<Animal> GetAllAnimals() {
        AnimalDataContext dataContext = new AnimalDataContext();
            return dataContext.GetAllAnimals();
}
AnimalDataContext
实现了
IDisposable
,因为我在那里有一个
XmlTextReader
,我想确保它很快得到清理

现在,如果我将第一个调用封装在一个using语句中,如下所示

public static IEnumerable<Animal> GetAllAnimals() {
        using(AnimalDataContext dataContext = new AnimalDataContext()) {
            return dataContext.GetAllAnimals();
        }
}
公共静态IEnumerable GetAllAnimals(){
使用(AnimalDataContext dataContext=new AnimalDataContext()){
返回dataContext.GetAllAnimals();
}
}
并在
AnimalDataContext.GetAllAnimals()
方法的第一行放置一个断点,在
AnimalDataContext.Dispose()
方法的第一行放置另一个断点,然后执行

首先调用
Dispose()
方法,以便
AnimalXmlReader.GetNames()
给出“对象引用未设置为对象实例”异常,因为
AnimalXmlReader
已在
Dispose()
中设置为
null


有什么想法吗?我有一种预感,它与
yield-return
相关,不允许在try-catch块内调用,而
使用
有效地表示,一旦编译

当您调用
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);
        }
    }
}
public static IEnumerable<Animal> GetAllAnimals() {
    using (AnimalDataContext dataContext = new AnimalDataContext()) {
        return new List<Animal>(dataContext.GetAllAnimals());
    }
}
公共静态IEnumerable GetAllAnimals(){
使用(AnimalDataContext dataContext=new AnimalDataContext()){
foreach(dataContext.GetAllAnimals()中的var animalName){
动物(动物名称);
}
}
}
这样,using语句将在外部迭代器中编译,并且仅当外部迭代器被释放时才会被释放

另一种解决方案是在包装器中枚举IEnumerable。最简单的方法是返回一个
列表
,如下所示:

public static IEnumerable<Animal> GetAllAnimals() {
    using (AnimalDataContext dataContext = new AnimalDataContext()) {
        foreach (var animalName in dataContext.GetAllAnimals()) {
            yield return GetAnimal(animalName);
        }
    }
}
public static IEnumerable<Animal> GetAllAnimals() {
    using (AnimalDataContext dataContext = new AnimalDataContext()) {
        return new List<Animal>(dataContext.GetAllAnimals());
    }
}
公共静态IEnumerable GetAllAnimals(){
使用(AnimalDataContext dataContext=new AnimalDataContext()){
返回新列表(dataContext.GetAllAnimals());
}
}

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

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

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

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

public static IEnumerable<Animal> GetAllAnimals() {
   using(AnimalDataContext dataContext = new AnimalDataContext()) {
      foreach (Animal animal in dataContext.GetAllAnimals()) {
         yield return animal;
      }
   }
}
公共静态IEnumerable GetAllAnimals(){
使用(AnimalDataContext dataContext=new AnimalDataContext()){
foreach(dataContext.GetAllAnimals()中的动物){
产回动物;
}
}
}

这基本上也是我遇到的问题之一,请看我的问题:谢谢SLaks-第二个选项成功了,它的代码行少,bug少!。该调用将进入位于WebForms项目表示层中的“AnimalDataContextAdapter”,特别是用于枚举集合,因此在延迟执行上没有真正的损失。我将其抽象为:永远不要在使用
yield-return
或其他延迟执行方法的方法中接受IDisposable参数。使用
yield-return
是安全的,并且在流上调用Dispose集合被完全枚举。这本质上意味着我只能使用yield return在内存集合中进行迭代,因为远程查询总是使用一些类来获取数据,这些类通常实现IDisposable。