Comment concevez-vous un énumérateur qui retourne (théoriquement) une quantité infinie d'éléments?

StackOverflow https://stackoverflow.com/questions/197297

  •  10-07-2019
  •  | 
  •  

Question

J'écris un code qui ressemble à ceci:

public IEnumerable<T> Unfold<T>(this T seed)
{
    while (true)
    {
        yield return [next (T)object in custom sequence];
    }
}

Évidemment, cette méthode ne va jamais revenir. (Le compilateur C # le permet en silence, tandis que R # me donne l'avertissement & "; La fonction ne renvoie jamais &"; .)

.

De manière générale, est-ce une mauvaise conception de fournir un énumérateur qui renvoie un nombre infini d’éléments, sans fournir de moyen permettant d’arrêter d’énumérer?

Existe-t-il des considérations spéciales pour ce scénario? Mem? Perf? Autres pièges?

Si nous fournissons toujours une condition de sortie, quelles sont les options? E.g:

  • un objet de type T qui représente la limite inclusive ou exclusive
  • a Predicate<T> continue (comme TakeWhile le fait)
  • un compte (comme Take le fait)
  • ...

Faut-il compter sur les utilisateurs qui appellent Take(...) / TakeWhile(...) après Unfold(...)? (Peut-être l'option préférée, car elle exploite les connaissances existantes de Linq.)

Répondriez-vous différemment à cette question si le code allait être publié dans une API publique, en l'état (générique) ou en tant qu'implémentation spécifique de ce modèle?

Était-ce utile?

La solution

Tant que vous documentez très clairement que la méthode ne terminera jamais l'itération (la méthode elle-même revient très rapidement, bien sûr), alors je pense que c'est bien. En effet, certains algorithmes peuvent être beaucoup plus propres. Je ne crois pas qu'il y ait des implications importantes en termes de mémoire / performances - bien que si vous vous référez à un & "Cher &"; objet dans votre itérateur, cette référence sera capturée.

Il y a toujours moyen d'abuser des API: tant que vos documents sont clairs, je pense que ça va.

Autres conseils

  

& "En règle générale, est-ce une mauvaise conception   fournir un énumérateur qui retourne   une quantité infinie d'objets, sans   fournir un moyen d'arrêter d'énumérer? "

Le consommateur du code peut toujours cesser d’énumérer (en utilisant une pause, par exemple ou d’autres moyens). Si votre énumérateur revient et votre séquence infinie, cela ne signifie pas que le client de l'énumérateur est en quelque sorte contraint de ne jamais interrompre l'énumération. En fait, vous ne pouvez pas créer d'énumérateur dont l'énumération est garantie par un client.

  

Faut-il compter sur les utilisateurs qui appellent   Prenez (...) / TakeWhile (...) after   Se dérouler(...)? (Peut-être le préféré   option, car elle exploite les   Connaissances Linq.)

Oui, tant que vous spécifiez clairement dans votre documentation que l'énumérateur est renvoyé et que la séquence infinie et l'interruption de l'énumération relèvent de la responsabilité de l'appelant, tout devrait bien se passer.

Renvoyer des séquences infinies n’est pas une mauvaise idée, les langages de programmation fonctionnels le font depuis longtemps maintenant.

Je suis d'accord avec Jon. Le compilateur transforme votre méthode en classe implémentant une machine à états simple qui conserve la référence à la valeur actuelle (c'est-à-dire la valeur qui sera renvoyée via la propriété Current). J'ai utilisé cette approche plusieurs fois pour simplifier le code. Si vous documentez clairement le comportement de la méthode, cela devrait fonctionner correctement.

Je n’utiliserais pas un énumérateur infini dans une API publique. Les programmeurs C #, y compris moi-même, sont trop habitués à la boucle foreach. Cela serait également compatible avec le .NET Framework; remarquez comment les méthodes Enumerable.Range et Enumerable.Repeat utilisent un argument pour limiter le nombre d'éléments dans Enumerable. Microsoft a choisi d’utiliser Enumerable.Repeat (& Quot; & Quot ;, 10) au lieu d’Enumerable.Repeat (& Quot & Quot;). Prenez (10) pour éviter l’énumération infinie et I adhérerait à leurs choix de conception.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top