2008-10-23 7 views

Répondre

15

L'infrastructure .Net requiert des chaînes d'être immuables. En raison de cette exigence, il est capable d'optimiser toutes sortes d'opérations.

String interning est un bon exemple de cette exigence est fortement exploité. Pour accélérer certaines comparaisons de chaînes (et réduire la consommation de mémoire), le framework .Net maintient un dictionnaire de pointeurs, toutes les chaînes prédéfinies seront dans ce dictionnaire ou dans toutes les chaînes sur lesquelles vous appelez la méthode String.intern. Lorsque l'instruction IL ldstr est appelée, elle vérifie le dictionnaire interne et évite l'allocation de mémoire si la chaîne est déjà affectée. Remarque: String.Concat ne vérifie pas les chaînes internées.

Cette propriété de l'infrastructure .net signifie que si vous commencez à déblayer directement avec des chaînes, vous pouvez corrompre votre table interne et à son tour corrompre d'autres références à la même chaîne.

Par exemple:

  // these strings get interned 
     string hello = "hello"; 
     string hello2 = "hello"; 

     string helloworld, helloworld2; 

     helloworld = hello; 
     helloworld += " world"; 

     helloworld2 = hello; 
     helloworld2 += " world"; 

     unsafe 
     { 
      // very bad, this changes an interned string which affects 
      // all app domains. 
      fixed (char* str = hello2) 
      { 
       *str = 'X'; 
      } 

      fixed (char* str = helloworld2) 
      { 
       *str = 'X'; 
      } 

     } 

     Console.WriteLine("hello = {0} , hello2 = {1}", hello, hello2); 
     // output: hello = Xello , hello2 = Xello 


     Console.WriteLine("helloworld = {0} , helloworld2 = {1}", helloworld, helloworld2); 
     // output : helloworld = hello world , helloworld2 = Xello world 
14

Y a-t-il des raisons pour lesquelles je devrais jamais faire cela?

Oui, très simple: Parce que .NET repose sur le fait que les chaînes sont immuables. Certaines opérations (par exemple, s.SubString(0, s.Length)) renvoient en fait une référence à la chaîne d'origine. Si cela est maintenant modifié, toutes les autres références le seront également.

Mieux vaut utiliser un StringBuilder pour modifier une chaîne car c'est la méthode par défaut.

+0

Je pensais que la méthode 'Substring' renvoyait toujours une nouvelle chaîne, du moins c'est ce que dit le doc msdn dans la section des remarques. Voir: [String.Substring, méthode (Int32, Int32)] (https://msdn.microsoft.com/en-us/library/aka44szs%28v=vs.110%29.aspx) – neodymium

1

Oh chéri seigneur oui.

1) Parce que cette classe n'est pas conçue pour être altérée.

2) Parce que les chaînes sont conçues et attendues dans tout le cadre pour être immuables. Cela signifie que le code que tout le monde écrit (y compris MSFT) s'attend à ce que la valeur sous-jacente d'une chaîne ne change jamais.

3) Parce que c'est l'optimisation prématurée et qui est E V I L.

5

Mettez cette façon: comment vous sentiriez-vous si un autre programmeur a décidé de remplacer 0 avec 1 partout dans votre code, au moment de l'exécution? Cela jouerait le diable avec toutes vos hypothèses. La même chose est vraie avec les cordes. Tout le monde s'attend à ce qu'ils soient immuables, et les codes avec cette hypothèse à l'esprit. Si vous violez cela, vous risquez d'introduire des bogues - et ils seront vraiment difficiles à retrouver.

+0

Je peux juste imaginer qu'ils sont utilisés dans un dictionnaire, oh homme qui ferait des ravages! – leppie

0

D'accord sur StringBuilder, ou simplement convertir votre chaîne en un tableau de caractères/octets et y travailler.Aussi, vous avez donné l'exemple de "upcasing" - la classe String a une méthode ToUpper, et si ce n'est pas au moins aussi vite que votre "upcasing" dangereux, je vais manger mon chapeau.

Questions connexes