someSsortingng.IndexOf (someSsortingng) renvoie 1 au lieu de 0 sous .NET 4

Nous avons récemment mis à niveau tous nos projets de .NET 3.5 vers .NET 4. J’ai rencontré un problème assez étrange concernant ssortingng.IndexOf() .

Mon code fait évidemment quelque chose de légèrement différent, mais en étudiant le problème, j’ai trouvé que l’appel de IndexOf() sur une chaîne avec elle-même renvoyait 1 au lieu de 0. En d’autres termes:

 ssortingng text = "\xAD\x2D"; // problem happens with "-dely N.China", too; int index = text.IndexOf(text); // see update note below. 

M’a donné un index de 1 au lieu de 0. Quelques remarques à propos de ce problème:

  • Les problèmes semblent liés à ces traits d’union (le premier caractère est le trait d’union Unicode, le second est un trait d’union régulier).

  • J’ai vérifié deux fois, cela ne se produit pas dans .NET 3.5 mais dans .NET 4.

  • Changer le IndexOf() pour faire une comparaison ordinale corrige le problème, donc pour une raison quelconque, le premier caractère est ignoré avec le IndexOf par défaut.

Est-ce que quelqu’un sait pourquoi cela se produit?

MODIFIER

Désolé les gars, fait un peu de choses sur le message original et obtenu le tiret caché à deux resockets. J’ai mis à jour la chaîne, cela devrait retourner l’index de 1 au lieu de 2, tant que vous le collez dans l’éditeur approprié.

Mettre à jour:

Changement de la chaîne de problèmes d’origine en une chaîne où chaque caractère réel est clairement visible (en utilisant l’échappement). Cela simplifie un peu la question.

Votre chaîne comporte deux caractères: un trait d’union doux (code Unicode 173) et un trait d’union (code Unicode 45).

Wiki : Selon le standard Unicode, un trait d’union doux n’est pas affiché si la ligne n’est pas cassée à ce moment.

Lorsque vous utilisez "\xAD\x2D".IndexOf("\xAD\x2D") dans .NET 4, il semble ignorer que vous recherchez le trait d’union, renvoyant un index de départ de 1 (l’index de \x2D ) . Dans .NET 3.5, cela retourne 0.

Plus amusant, si vous exécutez ce code (donc en ne recherchant que le trait d’union):

 ssortingng text = "\xAD\x2D"; ssortingng shy = "\xAD"; int i1 = text.IndexOf(shy); 

alors i1 devient 0, quelle que soit la version .NET utilisée. Le résultat de text.IndexOf(text); varie en effet, ce qui à première vue ressemble à un bug pour moi.

Autant que je puisse retracer à travers le framework, les anciennes versions de .NET utilisent un InternalCall vers IndexOfSsortingng() (je n’arrive pas à comprendre à quel appel d’API va), tandis que de .NET 4, un QCall vers InternalFindNLSSsortingngEx() est créé. , qui à son tour appelle FindNLSSsortingngEx() .

Le problème (je ne peux vraiment pas savoir si c’est le comportement prévu) se produit en effet lorsque vous appelez FindNLSSsortingngEx :

 LPCWSTR lpSsortingngSource = L"\xAD\x2D"; LPCWSTR lpSsortingngValue = L"\xAD"; int length; int i = FindNLSSsortingngEx( LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, lpSsortingngSource, -1, lpSsortingngValue, -1, &length, NULL, NULL, 1); Console::WriteLine(i); i = FindNLSSsortingngEx( LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, lpSsortingngSource, -1, lpSsortingngSource, -1, &length, NULL, NULL, 1); Console::WriteLine(i); Console::ReadLine(); 

Imprime 0 et ensuite 1. Notez que length , un paramètre out indiquant la longueur de la chaîne trouvée, est 0 après le premier appel et 1 après le second; le trait d’union est compté comme ayant une longueur de 0.

La solution consiste à utiliser text.IndexOf(text, SsortingngComparison.OrdinalIgnoreCase); , comme vous l’avez noté. Cela fait un QCall à InternalCompareSsortingngOrdinalIgnoreCase() qui à son tour appelle FindSsortingngOrdinal() , qui retourne 0 pour les deux cas.

Il semble y avoir un bogue dans .NET4 , et les nouvelles modifications apscopes à .NET4 Beta1 à la version précédente sont les mêmes que .NET 2.0 / 3.0 / 3.5 .

Quoi de neuf dans la BCL dans .NET 4.0 CTP (blogs MSDN) :

Modification de la sécurité des chaînes dans .NET 4

Les surcharges de correspondance partielle par défaut sur System.Ssortingng (StartsWith, EndsWith, IndexOf et LastIndexOf) ont été modifiées pour être indépendantes de la culture (ordinal) par défaut.

Cette modification a affecté le comportement de la méthode Ssortingng.IndexOf en les modifiant pour effectuer une comparaison ordinale (byte-by-byte) par défaut; elle sera modifiée pour utiliser CultureInfo.InvariantCulture au lieu de CultureInfo.CurrentCulture .

UPDATE pour .NET 4 Beta 1

Afin de maintenir une compatibilité élevée entre .NET 4 et les versions précédentes, nous avons décidé de revenir sur cette modification. Le comportement des surcharges de correspondance partielle par défaut de Ssortingng et des méthodes ToUpper et ToLower de Ssortingng and Char se comporte désormais comme dans .NET 2.0 / 3.0 / 3.5. Le retour au comportement d’origine est présent dans .NET 4 Beta 1.


Pour résoudre ce problème , remplacez la méthode de comparaison de chaînes par une surcharge qui accepte l’énumération System.SsortingngComparison tant que paramètre et spécifiez Ordinal ou OrdinalIgnoreCase .

 // ssortingng contains 'unicode dash' \x2D ssortingng text = "\xAD\x2D"; // woks in .NET 2.0/3.0/3.5 and .NET 4 Beta 1 and later // but seems be buggy in .NET 4 because of 'culture-sensitive' comparison int index = text.IndexOf(text); // fixed version index = text.IndexOf(text, SsortingngComparison.Ordinal); 

De la documentation (je souligne):

Cette méthode effectue une recherche par mot ( sensible à la casse et à la culture ) en utilisant la culture actuelle.

C’est à dire. certains points de code distincts seront traités comme égaux.

Que se passe-t-il si vous utilisez une surcharge prenant une valeur SsortingngComparison et transmettez SsortingngComparison.Ordinal pour éviter les dépendances culturelles?