Cela ressemble beaucoup au comportement que j'ai rencontré avec une propriété qui instancie une nouvelle instance d'un objet.
Vos sentiments sont corrects
En guise de préface à cette réponse, je tiens à souligner qu'en C#, nous pouvons stocker des méthodes dans des variables comme nous pouvons stocker des données :
var method = () => new MyObj();
En () => new MyObj()
est la "méthode" ; elle n'a pas de nom, ne prend aucun paramètre et renvoie un nouveau MyObj. Nous n'y faisons pas réellement référence en tant que méthode, nous avons tendance à l'appeler lambda, mais à toutes fins utiles, elle se comporte comme ce que vous connaissez en tant que "méthode" :
public MyObj SomeName(){
return new MyObj();
}
Vous pouvez probablement identifier les parties communes - le compilateur devine le type de retour, lui donne un nom en interne parce que nous ne nous en soucions pas et, lorsqu'il s'agit d'une seule instruction qui produit une valeur, le compilateur remplit le champ de l'instruction. return
mot-clé pour nous aussi. C'est une méthode logique très compacte.
Donc, revenons à cette variable appelée method
:
var method = () => new MyObj();
Vous pourriez l'exécuter comme :
var myObj = method.Invoke();
Vous pouvez même supprimer le mot Invoke et écrire simplement method()
mais je vais laisser Invoke pour le moment, pour plus de clarté. Lorsqu'elle est invoquée, la méthode s'exécute, renvoie une nouvelle donnée MyObj et cette donnée est stockée dans le fichier myObj
..
Ainsi, la plupart du temps, lorsque nous codons, une variable stocke des données, mais parfois elle stocke une méthode, et c'est pratique
Lorsque vous faites un Select LINQ, vous devez lui donner une méthode qui sera exécutée chaque fois que l'énumérable résultant sera énuméré :
var enumerable = new []{1,2,3}.Select(x => new MyObj());
Il n'exécute pas la méthode x => new MyObj()
que vous donnez au moment où vous appelez Select il ne génère pas de données ; il stocke simplement la méthode pour une utilisation ultérieure.
Chaque fois que vous bouclerez (énumérerez) ceci, il exécutera cette méthode ( x => new MyObj()
) jusqu'à 3 fois - je dis jusqu'à, parce que vous n'avez pas besoin d'énumérer complètement mais si vous le faites, il y a 3 éléments dans le tableau donc l'énumération peut causer au maximum 3 invocations de la méthode.
LINQ Select n'exécute pas la méthode et ne saisit pas les données - il crée effectivement une collection de méthodes fournissant des données plutôt qu'une collection de données.
Conceptuellement, c'est comme si Select vous produisait un tableau plein de méthodes :
var enumerable = new[]{
() => new MyObj(),
() => new MyObj(),
() => new MyObj()
};
Vous pourriez l'énumérer et exécuter ces méthodes vous-même :
foreach(var method in enumerable)
method.Invoke();
Votre Alter() a exécuté l'énumération (a fait une boucle), a récupéré chaque nouvel objet renvoyé par chaque méthode, l'a modifié, puis l'a jeté. Conceptuellement, votre méthode Alter a fait ceci :
foreach(var method in enumerable)
method.Invoke().Name = 5;
La méthode est exécutée, un nouveau MyObj est créé avec une valeur par défaut pour Name, puis Name est changé en 5, et les données de l'objet sont jetées.
Une fois que vous avez terminé votre Alter, vous l'avez à nouveau énuméré, de nouveaux objets ont été créés parce que les méthodes ont été exécutées à nouveau, le Nom était bien sûr inchangé - nouvel objet, aucun changement. Ici, rien n'est prévu pour se souvenir des données générées ; la seule chose dont on se souvient est la liste des méthodes qui génèrent ces données.
Lorsque vous mettez un ToList() à la fin, c'est différent - ToList énumère en interne l'énumérable, provoque l'exécution des méthodes qui génèrent les objets mais de manière critique. il stocke les objets résultants dans une liste et vous donne la liste des objets. Au lieu d'être une collection de méthodes qui fournissent des valeurs, c'est une collection de valeurs que vous pouvez modifier.
C'est comme si ça faisait ça :
var r = new List<MyObj>();
foreach(var method in enumerable)
r.Add(method.Invoke());
return r;
Cela signifie que vous obtenez une liste de données (pas une liste de méthodes qui fournissent des données), et si vous bouclez ensuite sur cette liste, vous modifiez les données qui sont stockées dans la liste, plutôt que d'exécuter des méthodes, de modifier la valeur renvoyée et de la jeter.