52 votes

déclaration return return dans un bloc using () {} Dispose avant l'exécution

J'ai écrit mon propre couche de données de persister à un fichier spécifique, et je l'ai captée avec un custom DataContext modèle.

C'est basé sur l' .NET Framework 2.0 (au vu des contraintes pour le serveur cible), alors même si certains de il pourrait ressembler à LINQ-to-SQL, ne l'est pas! J'ai juste mis en place un semblable modèle de données.

Voir l'exemple ci-dessous pour un exemple d'une situation que je ne peux pas encore expliquer.

Pour obtenir toutes les instances de l'Animal - je le faire et il fonctionne très bien

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

Et la mise en œuvre de la GetAllAnimals() la méthode dans le AnimalDataContext() ci-dessous

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

Le AnimalDataContext() implémente IDisposable parce que j'ai un XmlTextReader là-bas et je veux faire en sorte qu'il soit nettoyé rapidement.

Maintenant, si j'enveloppe le premier appel à l'intérieur d'une instruction d'utilisation comme

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

et mettre un point de rupture à la première ligne de la AnimalDataContext.GetAllAnimals() la méthode et d'un autre point de rupture à la première ligne dans le AnimalDataContext.Méthode dispose (), et de l'exécuter...

la méthode dispose() est appelée en PREMIER, de sorte que AnimalXmlReader.Getnames a() donne "la référence d'objet n'est pas définie à l'instance de l'objet" d'exception parce que AnimalXmlReader a été définie à null dans la dispose() ???

Des idées? J'ai un pressentiment que son liés à des taux de retour n'étant pas autorisés à être appelée à l'intérieur d'un bloc try-catch, qui aide efficacement représente, une fois compilé...

60voto

SLaks Points 391154

Lorsque vous appelez GetAllAnimals il ne fait pas exécuter le code jusqu'à ce que vous énumérez de l'interface IEnumerable retournée dans une boucle foreach.

Le dataContext est en train d'être éliminés dès que le wrapper méthode retourne, avant de vous énumérer l'interface IEnumerable.

La solution la plus simple serait de faire la méthode wrapper un itérateur ainsi, comme ceci:

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

De cette façon, l'utilisation de déclaration seront compilées dans l'extérieur itérateur, et il ne sera disposé quand l'extérieur itérateur est éliminé.

Un autre soluton serait d'énumérer les IEnumerable dans l'emballage. Le plus simple serait de revenir à un List<Animal>, comme ceci:

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

Notez que ce perd le bénéfice de l'exécution différée, donc il va obtenir tous les animaux, même si vous n'en avez pas besoin.

12voto

Guffa Points 308133

La raison pour cela est que la GetAllAnimals méthode ne retourne pas une collection d'animaux. Elle renvoie un énumérateur qui est capable de retourner un animal à la fois.

Lorsque vous retourner le résultat de la GetAllAnimals appeler à l'intérieur de la à l'aide de bloc, vous avez juste retour de l'agent recenseur. L'utilisation de bloc dispose le contexte de données avant que la méthode existe, et à ce moment, l'agent recenseur n'ai pas encore lu tout les animaux et à toutes. Lorsque vous essayez d'utiliser l'agent recenseur, il ne peut pas en avoir d'animaux à partir des données de contexte.

Une solution est de faire la GetAllAnimals méthode également créer un agent recenseur. De cette façon, l'utilisation de bloc ne sera pas fermée jusqu'à l'arrêt de l'aide que l'agent recenseur:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X