Il s'agit d'un cas d'abstraction non étanche. Une propriété est en fait une méthode, le obtenir y fixer pour un indexeur sont compilés dans les méthodes get_Index() et set_Index. Le compilateur fait un excellent travail pour cacher ce fait, il traduit automatiquement une affectation à une propriété par la méthode set_Xxx() correspondante, par exemple.
Mais cela ne fonctionne plus du tout lorsque vous passez un paramètre de méthode par référence. Le compilateur JIT doit alors passer un pointeur sur l'emplacement mémoire de l'argument passé. Le problème est qu'il n'y en a pas, l'assignation de la valeur d'une propriété nécessite d'appeler la méthode setter. La méthode appelée ne peut pas faire la différence entre une variable passée et une propriété passée et ne peut donc pas savoir si un appel de méthode est nécessaire.
Ce qui est remarquable, c'est que cela fonctionne en fait en VB.NET. Par exemple :
Class Example
Public Property Prop As Integer
Public Sub Test(ByRef arg As Integer)
arg = 42
End Sub
Public Sub Run()
Test(Prop) '' No problem
End Sub
End Class
Le compilateur VB.NET résout ce problème en générant automatiquement ce code pour la méthode Run, exprimée en C# :
int temp = Prop;
Test(ref temp);
Prop = temp;
C'est la solution de contournement que vous pouvez également utiliser. Je ne sais pas exactement pourquoi l'équipe C# n'a pas utilisé la même approche. Peut-être parce qu'ils ne voulaient pas cacher les appels potentiellement coûteux des getter et setter. Ou le comportement totalement non diagnostiqué que vous obtiendrez lorsque le setter a des effets secondaires qui modifient la valeur de la propriété, ils disparaîtront après l'assignation. Différence classique entre C# et VB.NET, C# est "sans surprise", VB.NET est "faites en sorte que cela fonctionne si vous le pouvez".