52

特定のファイルに永続化する独自のカスタム データ レイヤーを作成し、それをカスタム DataContext パターンで抽象化しました。

これはすべて .NET 2.0 Framework に基づいているため (ターゲット サーバーに制約がある場合)、その一部は 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実装します。IDisposableXmlTextReader

最初の呼び出しを using ステートメントでラップすると、

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

メソッドの最初の行にブレークポイントを置き、AnimalDataContext.GetAllAnimals()メソッドの最初の行に別のブレークポイントを置き、AnimalDataContext.Dispose()実行します...

メソッドはDispose()FIRST と呼ばれ、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」という例外が発生します。AnimalXmlReader.GetNames()AnimalXmlReadernullDispose()

何か案は?yield returntry-catch ブロック内で呼び出すことが許可されていないことに関連しているという予感があります。これusingは、コンパイルされると効果的に表されます...

4

2 に答える 2

60

呼び出しGetAllAnimalsても、返された IEnumerable を foreach ループで列挙するまで、実際にはコードは実行されません。

IEnumerable を列挙する前に、ラッパー メソッドが返されるとすぐに dataContext が破棄されます。

最も簡単な解決策は、次のようにラッパー メソッドもイテレータにすることです。

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

このように、using ステートメントは外側の反復子でコンパイルされ、外側の反復子が破棄されたときにのみ破棄されます。

別の解決策は、ラッパーで IEnumerable を列挙することです。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 に答える