Un champ statique en lecture seule ne peut être attribué à
Vous ne l'assignez pas. Vous appelez des fonctions publiques dans le System.Reflection
espace de noms. Il n'y a aucune raison pour que le compilateur se plaigne de cela.
D'ailleurs, typeof(string).GetField("Empty")
pourrait utiliser des variables entrées par l'utilisateur à la place, il n'y a pas de moyen sûr pour le compilateur de dire dans tous les cas si l'argument de la fonction GetField
finira par être "Empty"
.
Je pense que vous voulez Reflection
pour voir que le champ est marqué initonly
et lancer une erreur au moment de l'exécution. Je peux comprendre pourquoi vous vous attendez à cela, mais pour les tests en boîte blanche, même l'écriture dans le fichier initonly
Les champs ont une certaine application.
La raison pour laquelle NGEN n'a aucun effet est que vous ne modifiez pas de code ici, seulement des données. Les données sont stockées en mémoire avec .NET comme avec tout autre langage. Les programmes natifs peuvent utiliser des sections de mémoire en lecture seule pour des choses comme les constantes de chaîne, mais le pointeur vers la chaîne est généralement toujours accessible en écriture et c'est ce qui se passe ici.
Notez que votre code doit être exécuté avec une confiance totale pour utiliser la réflexion de cette manière discutable. De plus, le changement n'affecte qu'un seul programme, ce n'est pas une sorte de vulnérabilité de sécurité comme vous semblez le penser (si vous exécutez du code malveillant dans votre processus avec une confiance totale, cette décision de conception est le problème de sécurité, pas la réflexion).
Notez également que les valeurs de initonly
champs intérieurs mscorlib.dll
sont des invariants globaux du runtime .NET. Après les avoir brisés, vous ne pouvez même pas tester de manière fiable si l'invariant a été brisé, car le code permettant d'inspecter la valeur actuelle de System.String.Empty a également été brisé, parce que vous avez violé ses invariants. Commencez à violer les invariants du système et vous ne pourrez plus vous fier à rien.
En spécifiant ces valeurs dans les spécifications .NET, le compilateur peut mettre en œuvre toute une série d'optimisations des performances. Un exemple simple est que
s == System.String.Empty
et
(s != null) && (s.Length == 0)
sont équivalentes, mais la seconde est beaucoup plus rapide (relativement parlant).
Le compilateur peut également déterminer que
if (int.Parse(s) > int.MaxValue)
n'est jamais vrai, et génère un saut inconditionnel vers le bloc else (il doit encore appeler Int32.Parse
pour avoir le même comportement d'exception, mais la comparaison peut être supprimée).
System.String.Empty
est également très utilisé dans les implémentations de la BCL. Si vous l'écrasez, toutes sortes de choses folles peuvent se produire, y compris des dommages qui fuient en dehors de votre programme. (par exemple, vous pouvez écrire dans un fichier dont le nom est construit à l'aide de la manipulation de chaînes de caractères... lorsque la chaîne de caractères se rompt, vous risquez d'écraser le mauvais fichier).
Et le comportement peut facilement varier selon les versions de .NET. Normalement, lorsque de nouvelles possibilités d'optimisation sont trouvées, elles ne sont pas reportées dans les versions précédentes du compilateur JIT (et même si elles l'étaient, il pourrait y avoir des installations antérieures à la mise en œuvre du report). En particulier. String.Empty
-Les optimisations liées à .NET sont sensiblement différentes entre .NET 2.x et Mono et .NET 4.5+.