Pourquoi ne peut-itérateur méthodes, prendre le " ref " ou " out " paramètres?
J'ai essayé plus tôt aujourd'hui:
public interface IFoo
{
IEnumerable<int> GetItems_A( ref int somethingElse );
IEnumerable<int> GetItems_B( ref int somethingElse );
}
public class Bar : IFoo
{
public IEnumerable<int> GetItems_A( ref int somethingElse )
{
//Ok...
}
public IEnumerable<int> GetItems_B( ref int somethingElse )
{
yield return 7; //CS1623: Iterators cannot have ref or out parameters
}
}
Quelle est la logique derrière cela?
- Fait quelque chose de se produire lorsque vous avez essayé cela, ou nous demandez-vous pour votre justification pour l'essayer?
- Je discuter de certains de ces considérations de conception ici: blogs.msdn.com/ericlippert/archive/2009/05/04/...
- solution moderne: answers.unity3d.com/answers/551381/view.html
Vous devez vous connecter pour publier un commentaire.
C# itérateurs sont des machines d'état à l'interne. Chaque fois que vous
yield return
quelque chose, l'endroit où vous l'avez laissé devrait être enregistré en même temps que l'état des variables locales de sorte que vous pouvez revenir et continuer à partir de là.De tenir cet état, compilateur C# crée une classe afin de conserver les variables locales et la place qu'elle doit continuer à partir. Il n'est pas possible d'avoir un
ref
ouout
valeur d'un champ dans une classe. Par conséquent, si vous avez été autorisé à déclarer un paramètre commeref
ouout
, il n'y aurait pas moyen de garder la photo complète de la fonction au moment où nous l'avions laissé.EDIT: Techniquement, pas toutes les méthodes qui retournent des
IEnumerable<T>
sont considérés comme des itérateurs. Seulement ceux qui utilisentyield
de produire directement une séquence sont considérés comme des itérateurs. Par conséquent, alors que le fractionnement de l'itérateur en deux méthodes est une belle solution de contournement commune, il n'est pas en contradiction avec ce que je viens de dire. L'extérieur de la méthode (qui n'utilise pasyield
directement) est pas considéré comme un itérateur.ref
" variables ne seraient pas en mesure de les voir en train de changer.Si vous souhaitez retourner un itérateur et un int à partir de votre méthode, une solution de contournement est: est-ce
Vous devriez noter que rien dans le code à l'intérieur d'une méthode d'itérateur (c'est à dire essentiellement une méthode qui contient
yield return
ouyield break
) est exécutée jusqu'à ce que leMoveNext()
méthode dans l'Énumérateur est appelé. Donc, si vous avez été en mesure d'utiliserout
ouref
dans votre méthode d'itérateur, vous obtenez le comportement étonnant comme ceci:C'est un piège classique, une question est: est-ce
Donc un bon modèle est de séparer itérateur méthodes en deux parties: une pour l'exécuter immédiatement et l'autre qui contient le code qui doit être paresseusement exécuté.
EDIT:
Si vous voulez vraiment le comportement en mouvement où l'itérateur serait de modifier la
ref
-paramètre, vous pourriez faire quelque chose comme ceci:À un highish niveau, Une référence de variable peut point à de nombreux endroits, y compris à des types de valeur sur la pile. L'heure à laquelle l'itérateur est d'abord créé par l'appel de la méthode de l'itérateur et quand la ref variable serait attribué deux époques très différentes. Il n'est pas possible de garantir que la variable qui à l'origine a été adoptée par la référence est toujours là quand l'itérateur exécute. Par conséquent, il n'est pas permis (ou vérifiable)
D'autres ont expliqué pourquoi votre itérateur peut pas avoir un paramètre de référence. Voici une alternative simple:
Si vous avez plusieurs articles à passer dans et hors, de définir une classe pour les tenir.
J'ai contourné ce problème en utilisant des fonctions, lorsque la valeur que j'ai besoin de retour est dérivé de la itéré éléments: