Je ne comprends pas à quel point la fonction peut être nulle et la fonction Linq dernier () peut renvoyer un objet. Je pensais que la dernière utilise Getenumerator et continue à aller jusqu'à présent == null et retourne l'objet. Cependant, comme vous pouvez voir le premier getenumerator (). Le courant est NULL et la dernière en quelque sorte renvoie un objet.
Comment Linq Dernier () fonctionne? P>
items.GetEnumerator().Current items.Last()
5 Réponses :
La mise en œuvre peut donc être quelque chose comme ceci: p> (ceci pourrait être mis en œuvre avec un dernier () code> appelle getenumerator () code>, alors continuez à appeler movenext () code> / actuel code> Code> MOVENEXT () CODE> retourne false, à quel point il renvoie la dernière valeur de actuel code> récupéré. La nullité n'est pas utilisée comme un terminateur dans des séquences, généralement. pour code> boucle, mais ce qui précède montre l'interaction plus explicitement. Cela ignore également la possibilité d'accéder directement au dernier élément.) p> p>
En outre, ne Collection.getenumerator (). Current code> retourner "L'objet avant le premier élément de la collection"? Ne faisait pas partie du contrat que vous devez appeler MOVENNext au moins une fois avant que le courant ait une valeur définie?
@Lasse: Oui, bien que IIRC Les blocs d'itérateurs générés par C # ignorent ceci :(
movenext () code> est i> appelé avant actuel code>, dans le bloc code> si code> bloque.
de l'utilisation de réflecteur sur system.core.dll code >: public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
TSource current;
do
{
current = enumerator.Current;
}
while (enumerator.MoveNext());
return current;
}
}
}
throw Error.NoElements();
}
La toute première valeur d'un énumérateur, avant tout MOVENNEXT (), est, dans le cas d'une matrice, l'élément à l'index -1.
Vous devez faire MOVENNEXT une fois pour entrer la collection.
Ceci est fait de manière à ce que le constructeur de l'énumérateur ne fonctionne pas beaucoup de travail, et de sorte que ces constructions soient valides:
while (enumerator.MoveNext()) {
// Do Stuff
}
if(enumerator.MoveNext()) {
// Do Stuff
} // This is identical to Linq's .Any(), essentially.
N'oubliez pas que l'appelant (je pense ...) p> getenumerator code> ne renvoie pas typiquement / nécessairement le même énumérateur code> à chaque fois. De plus, étant donné que chose.bettenumerator () code> renvoie un nouveau énumérateur code> qui commencera non initialisé (vous n'avez pas appelé movenext () code> pour le moment), < Code> chose.getenumerator (). Current code> em> sera toujours null par définition. p>
Le résultat est indéfini, typiquement nul, mais non défini néanmoins.
Si vous jetez un coup d'œil à Interface Ienumerator dans les remarques section, ils indiqueront les éléments suivants: p>
initialement fort>, l'énumérateur est
positionné avant le premier élément fort> dans la collection. à cette position, le courant est indéfini. strong> Par conséquent, vous devez appeler MOVENNEXT pour faire progresser l'énumérateur au premier élément de la collection avant de lire la valeur du courant. P> blockQuote> Vous devez donc appeler
movenext () code> une fois pour obtenir le premier élément. Sinon, vous n'aurez rien. P>
Cela explique ce qui n'allait pas avec mon processus de pensée. Merci!
Vous confondez des séquences avec leurs énumérateurs. Imaginez un livre avec des pages numérotées. C'est une séquence. Imaginez un signet, marquant une page particulière. C'est un énumérateur. Vous pouvez avoir une centaine de signets dans un livre si vous voulez, tous marquant différents endroits. Calling Getenumerator.Current demande à la page qu'un signet est sur le moment où vous ne l'avez même pas encore mis dans le livre; Ne fais pas ça.