Runtime: .NET Core 3.0-> .NET 5.0からのstring.IndexOf(string)による重大な変更

作成日 2020年10月22日  ·  76コメント  ·  ソース: dotnet/runtime

説明

.NET 5.0をサポートするようにパッケージを拡張しているところ、重大な変更が発生しました。 コンソールアプリケーションを考えると:

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var actual = "Detail of supported commands\n============\n## Documentation produced for DelegateDecompiler, version 0.28.0 on Thursday, 22 October 2020 16:03\n\r\nThis file documents what linq commands **DelegateDecompiler** supports when\r\nworking with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF).\r\nEF has one of the best implementations for converting Linq `IQueryable<>` commands into database\r\naccess commands, in EF's case T-SQL. Therefore it is a good candidate for using in our tests.\r\n\r\nThis documentation was produced by compaired direct EF Linq queries against the same query implemented\r\nas a DelegateDecompiler's `Computed` properties. This produces a Supported/Not Supported flag\r\non each command type tested. Tests are groups and ordered to try and make finding things\r\neasier.\r\n\r\nSo, if you want to use DelegateDecompiler and are not sure whether the linq command\r\nyou want to use will work then clone this project and write your own tests.\r\n(See [How to add a test](HowToAddMoreTests.md) documentation on how to do this). \r\nIf there is a problem then please fork the repository and add your own tests. \r\nThat will make it much easier to diagnose your issue.\r\n\r\n*Note: The test suite has only recently been set up and has only a handful of tests at the moment.\r\nMore will appear as we move forward.*\r\n\r\n\r\n### Group: Unit Test Group\n#### [My Unit Test1](../TestGroup01UnitTestGroup/Test01MyUnitTest1):\n- Supported\n  * Good1 (line 1)\n  * Good2 (line 2)\n\r\n#### [My Unit Test2](../TestGroup01UnitTestGroup/Test01MyUnitTest2):\n- Supported\n  * Good1 (line 1)\n  * Good2 (line 2)\n\r\n\r\n\nThe End\n";

            var expected = "\n#### [My Unit Test2](";

            Console.WriteLine($"actual.Contains(expected): {actual.Contains(expected)}");
            Console.WriteLine($"actual.IndexOf(expected): {actual.IndexOf(expected)}");
        }
    }
}

.NET Core 3.0-> .NET5.0のランタイムに基づいて異なる結果が得られます。

.NET Core 3.0:

actual.Contains(expected): True
actual.IndexOf(expected): 1475

.NET 5.0:

actual.Contains(expected): True
actual.IndexOf(expected): -1

構成

Windows 10Proビルド19041x64
.NET Core 3.1.9
.NET 5.0.0-rc.2.20475.5

回帰?

はい、.NET Core3.1.9で機能しました

area-System.Globalization question

最も参考になるコメント

@tarekghContainsIndexOf結果の違い自体は問題ではないことに同意します。

問題は明らかにIndexOfであり、別のASCIIのみの文字列内で1つのASCIIのみの文字列を見つけることができません(ASCIIのみの文字列にロケール依存の動作が課されたことはありません!)。

これは、ロケール/ NLS / ICU関連の変更から私が期待するものではありません。 実際、私は他のプログラミング言語/ランタイムがそのように動作することを考えることができませんでした。

これは、.NET 5 RC 2で壊れた(つまり、まったく予期しない結果をもたらす)単純化されたテストケースです。

var actual = "\n\r\nTest";
var expected = "\nTest";

Console.WriteLine($"actual.IndexOf(expected): {actual.IndexOf(expected)}"); // => -1

それは本当にそのように機能する必要がありますか? また、なぜですか? それは実際に何をしようとしているのですか?

それは本当に計画された変更でしたか?

はい、ICUへの切り替えは、さまざまな理由で意図的に変更されています。

申し訳ありませんが、これが計画された変更であるとは思わないので、強調したいと思います。そのような変更を_計画_している人は誰も想像できませんでした。 同様に、.NETチームの人々が一緒に座って話し合いました。

文字列 "\ n \ r \ nTest"には、ICUが有効になっている "\ nTest"が含まれていますか? いいえ、明らかにそうではありません!

そして、誰も文句を言いませんでしたか? チャンスではありません!

これは、計画または予想される変更のようには見えませんが、代わりに非常に深刻なバグ、大きな互換性ブロッカーのように見えます。 そのため、新しく移植された.NETアプリケーションは、文字列内の部分文字列を見つけることができないため、新しいランタイムでは正しく機能しません。

とにかくICUが行末を気にするのはなぜですか? 一部のロケールには、独自のロケール固有の行末がありますか?

PSはい、序数のフラグのように、文化に依存しないIndexOfバリアントを常に呼び出す必要があると主張することができます。 あなたは.NET 5に_that_ハードそれを破ることにしました場合でも、あなたはちょうどそれが、その後正気、序デフォルトを使用して作ることができませんでしたか? .NET 5 RC2で見られる現在の変更よりも破損するアプリケーションが少ないと思います。

また、 IndexOf常に文化固有の方法で動作しますが、序数のフラグなしでIndexOfを使用するコードが実際には_トン_あり、そのコードがあることは誰もが理解していると思います。 _以前は機能していました_(少なくとも一部/ほとんどの場合)。 また、.NET5の更新後に機能しなくなります。

全てのコメント76件

@tarekgh

このエリアへのサブスクライバーのタグ付け: @ tarekgh@ safern 、@ krwq
購読したい場合は、area-owners.mdの情報を参照してください。

これは、NLSの代わりにICUを使用して切り替えた.NET5.0の設計によるものです。 詳細については、 https://docs.microsoft.com/en-us/dotnet/standard/globalization-localization/globalization-icuを参照してください。

構成スイッチSystem.Globalization.UseNlsを使用して古い動作に戻すオプションがありますが、ICUの方が正確であり、ICUを使用して先に進むと、OS間で一貫性が得られるため、これを行うことはお勧めしません。

IndexOfContainsとして動作させたい場合は、その時点で序数比較を使用する必要があることを忘れてしまいました。

C# actual.IndexOf(expected, StringComparison.Ordinal)

構成スイッチSystem.Globalization.UseNlsを使用して古い動作に戻すオプションがありますが、ICUの方が正確であり、ICUを使用して先に進むと、OS間で一貫性が得られるため、これを行うことはお勧めしません。

ええ、 netcoreapp3.1をターゲットにしてUnixでこのコードを実行すると、同じ動作が見られます。

 santifdezm  DESKTOP-1J7TFMI  ~  experimental  indexof  $   /home/santifdezm/experimental/indexof/bin/Debug/netcoreapp3.1/linux-x64/publish/indexof
actual.Contains(expected): True
actual.IndexOf(expected): -1

そして、 Ordinal比較の@tarekghとして、期待される結果を返します。

 santifdezm  DESKTOP-1J7TFMI  ~  experimental  indexof  $  /home/santifdezm/experimental/indexof/bin/Debug/net5.0/linux-x64/publish/indexof
actual.Contains(expected): True
actual.IndexOf(expected): 1475

ソース文字列に\r\n\nが混在しているため、これは失敗していると思います。 \r\nすべてのインスタンスを\nに置き換えると、機能します。 すべてを\r\n場合も、同じことが言えます。 ICUの比較から異なる結果をもたらしているのは単なる混合です。

Twitterで報告されている問題は、5.0ランタイム内で、同じ入力でstring.IndexOfと、呼び出しごとに異なる結果が得られることでした。

https://twitter.com/jbogard/status/1319381273585061890?s=21

編集:上記は誤解でした。

@GrabYourPitchforksでは、問題のタイトルを更新できますか? これは技術的な重大な変更であるため、これはWindowsとUnixで発生します...そうですか?

明確にするために、ジミーにオフラインでpingを実行しました。 彼の元の問題報告を誤解した可能性があります。 280文字のフォーラムは、バグを明確に伝えるのに必ずしも効率的ではありません。 ;)

明確にするために、 Contains APIは通常の操作を実行しています。 文字列比較フラグのないIndexOfは言語操作であり、通常ではありません。 含む動作をIndexOfと比較する場合は、 IndexOf(expected, StringComparison.Ordinal)を使用する必要があります。
違いについて詳しく知る必要がある場合は、 https://docs.microsoft.com/en-us/dotnet/csharp/how-to/compare-stringsが便利なリンクです。

Twitterで説明を受けました。 アプリはループでIndexOfを呼び出していません。 これは、標準の3.0と5.0の動作の違いに関するレポートです。

@GrabYourPitchforks Twitterの返信でリンクhttps://docs.microsoft.com/en-us/dotnet/standard/globalization-localization/globalization-icuを共有し、古い動作に戻すための構成スイッチがあることを伝えてください。

Twitterで説明を受けました。 アプリはループ内でIndexOfを呼び出していません。 これは、標準の3.0と5.0の動作の違いに関するレポートです。

ありがとう、@ GrabYourPitchforks ...これに基づいて、設計どおりに閉じます。

ここにさらに追加するには、NLSに戻らずに古い動作を取得したい場合は、次のことができます。

`` `C#
CultureInfo.CurrentCulture.CompareInfo.IndexOf(actual、expected、CompareOptions.IgnoreSymbols)


or 

```C#
    actual.IndexOf(expected, StringComparison.Ordinal)

の代わりに

C# actual.IndexOf(expected)

そして、あなたは望ましい振る舞いを得るはずです。

リンクされたICU関連のドキュメント(https://docs.microsoft.com/en-us/dotnet/standard/globalization-localization/)に\r\n\n違いがわかりません。グローバリゼーション-icu)。

それは本当に計画された変更でしたか?

@ForNeVeRICUとNLSのすべての違いをリストするのは難しいでしょう。 この文書は、ICUへの切り替えの主な変更について説明しています。 私は前に先に指摘したように、それは右の結果を比較することではありませんContainsしてIndexOf StringComparisonパラメーターなし。 必要に応じて、以前の動作を取得する方法をいくつか上に示しました。 この問題のレポートから、IndexOfの使用には序数オプションを使用する必要があるように見えます。そのような場合に言語比較を使用するのは正しくありません。 このような場合に言語比較を使用することは、異なる環境で異なる結果をもたらす可能性のある現在の文化に依存する可能性があります。

それは本当に計画された変更でしたか?

はい、ICUへの切り替えは、さまざまな理由で意図的に変更されています。 Windowsは現在NLS上でICUの使用を推進しています。 とにかくICUは未来です。 また、ICUは、Windows / Linux / OSXまたはサポートされているプラ​​ットフォーム間で一貫した動作をする機会を提供します。 ICUを使用すると、アプリが必要に応じてグローバリゼーション動作をカスタマイズする機会が与えられます。

ドキュメントに示されているように、必要に応じて古い動作に戻すオプションがあります。

参照されているドキュメントによると、WindowsでのICU / NLSの動作は、実際の環境でのicu.dll可用性に基づいてサイレントに切り替わる可能性があります。 これは、公開されている自己完結型アプリにとって大きな驚きとなる可能性があります。 ICUはすべてのターゲット環境で使用できるわけではないため、切り替えが決定された場合、.NETはこの問題を回避するためにICUを出荷することを期待しています。 このオプションのランタイム依存関係は、物事をさらに面白くします。

ICUはすべてのターゲット環境で使用できるわけではないため、切り替えが決定された場合、.NETはこの問題を回避するためにICUを出荷することを期待しています。 このオプションのランタイム依存関係は、物事をさらに面白くします。

ICUは現在NuGetパッケージとして公開されています。 アプリはこのようなパッケージを使用して、自己完結型アプリにICUを確実に持たせることができます。 ドキュメント

@tarekghContainsIndexOf結果の違い自体は問題ではないことに同意します。

問題は明らかにIndexOfであり、別のASCIIのみの文字列内で1つのASCIIのみの文字列を見つけることができません(ASCIIのみの文字列にロケール依存の動作が課されたことはありません!)。

これは、ロケール/ NLS / ICU関連の変更から私が期待するものではありません。 実際、私は他のプログラミング言語/ランタイムがそのように動作することを考えることができませんでした。

これは、.NET 5 RC 2で壊れた(つまり、まったく予期しない結果をもたらす)単純化されたテストケースです。

var actual = "\n\r\nTest";
var expected = "\nTest";

Console.WriteLine($"actual.IndexOf(expected): {actual.IndexOf(expected)}"); // => -1

それは本当にそのように機能する必要がありますか? また、なぜですか? それは実際に何をしようとしているのですか?

それは本当に計画された変更でしたか?

はい、ICUへの切り替えは、さまざまな理由で意図的に変更されています。

申し訳ありませんが、これが計画された変更であるとは思わないので、強調したいと思います。そのような変更を_計画_している人は誰も想像できませんでした。 同様に、.NETチームの人々が一緒に座って話し合いました。

文字列 "\ n \ r \ nTest"には、ICUが有効になっている "\ nTest"が含まれていますか? いいえ、明らかにそうではありません!

そして、誰も文句を言いませんでしたか? チャンスではありません!

これは、計画または予想される変更のようには見えませんが、代わりに非常に深刻なバグ、大きな互換性ブロッカーのように見えます。 そのため、新しく移植された.NETアプリケーションは、文字列内の部分文字列を見つけることができないため、新しいランタイムでは正しく機能しません。

とにかくICUが行末を気にするのはなぜですか? 一部のロケールには、独自のロケール固有の行末がありますか?

PSはい、序数のフラグのように、文化に依存しないIndexOfバリアントを常に呼び出す必要があると主張することができます。 あなたは.NET 5に_that_ハードそれを破ることにしました場合でも、あなたはちょうどそれが、その後正気、序デフォルトを使用して作ることができませんでしたか? .NET 5 RC2で見られる現在の変更よりも破損するアプリケーションが少ないと思います。

また、 IndexOf常に文化固有の方法で動作しますが、序数のフラグなしでIndexOfを使用するコードが実際には_トン_あり、そのコードがあることは誰もが理解していると思います。 _以前は機能していました_(少なくとも一部/ほとんどの場合)。 また、.NET5の更新後に機能しなくなります。

問題は明らかにIndexOfであり、別のASCIIのみの文字列内で1つのASCIIのみの文字列を見つけることができません(ASCIIのみの文字列にロケール依存の動作が課されたことはありません!)。

ASCIIはロケールに依存しないというのは真実ではありません。 文化によってASCII文字の動作がどのように異なるかを示す例として、リンクhttp://userguide.icu-project.org/collat​​ion/conceptsを参照してください。

For example, in the traditional Spanish sorting order, "ch" is considered a single letter. All words that begin with "ch" sort after all other words beginning with "c", but before words starting with "d".
Other examples of contractions are "ch" in Czech, which sorts after "h", and "lj" and "nj" in Croatian and Latin Serbian, which sort after "l" and "n" respectively.

また、ICUが多くの専門家によってよく考えられているUnicode標準からデータと動作を選択していることを明確にしたいと思います。 @GrabYourPitchforksは、ここで話している\r\n\ケースの詳細を投稿します。 ただし、その間、特に次のセクションで、ドキュメントhttps://unicode.org/reports/tr29/に精通している可能性があります。

Do not break between a CR and LF. Otherwise, break before and after controls.
--
GB3 | CR | × | LF
GB4 | (Control \| CR \| LF) | ÷ |  
GB5 |   | ÷ | (Control \| CR \| LF)

とにかくICUが行末を気にするのはなぜですか? 一部のロケールには、独自のロケール固有の行末がありますか?

これについては、最後の段落で説明します。

申し訳ありませんが、これが計画された変更であるとは思わないので、強調したいと思います。そのような変更を計画している人は誰も想像できませんでした。 同様に、.NETチームの人々が一緒に座って話し合いました。
これは、計画または予想される変更のようには見えませんが、代わりに非常に深刻なバグ、大きな互換性ブロッカーのように見えます。 そのため、新しく移植された.NETアプリケーションは、文字列内の部分文字列を見つけることができないため、新しいランタイムでは正しく機能しません。

これはよく計画された作業であり、深く考えられています。 ずっと前に公開して公開した問題https://github.com/dotnet/runtime/issues/826
グローバリゼーションの振る舞いは、.NETだけでなく、OSやその他のプラットフォームでもいつでも変更される可能性があることも強調したいと思います。 これが、アプリが特定のICUバージョンを使用して、使用する動作が変更されないようにするICUアプリローカル機能をサポートした理由でもあります。 もう1つ、Windows自体がICUの使用を促進する過程にあり、いつの日かICUの動作がユーザーの大多数が使用することになるでしょう。

序数の旗のように。 しかし、.NET 5でそれを一生懸命やめることにした場合は、正気で通常のデフォルトを使用するようにすることはできませんか? .NET 5 RC2で見られる現在の変更よりも破損するアプリケーションが少ないと思います。

実際、Silverlightのリリース中は、以前に序数の動作をデフォルトとして作成しようとしましたが、ここで報告されているよりもはるかに多くの問題が発生しました。 開発者がIndexOfようなものを呼び出すときに意識し、意図を表すために意図的にStringComparisonフラグを提供するのに役立つ方法をさらに検討しています。 あなたが思いついたアイデアも歓迎します。

また、IndexOfは常にカルチャ固有の方法で動作しますが、序数フラグなしでIndexOfを使用するコードが実際には大量にあり、そのコードは以前は機能していたことを私たちは皆理解していると思います(ほとんどの場合、少なくとも)。 また、.NET5の更新後に機能しなくなります。

そのため、必要に応じて古い動作に戻すための構成スイッチを提供しています。 System.Globalization.UseNlsを見て

@tarekgh 、徹底的な説明をありがとう!

今のところ、この特定の\r\n動作の詳細を待つ方が良いと思います。 IndexOfがこの特定の検索を実行するときに「書記素クラスター境界ルール」をどのように使用するか(およびそれを実行する必要があるかどうか)は私にはわかりません。

また、Unicode仕様がここに関連している場合でも(これは非常によくあるかもしれません!)、 https://unicode.org/reports/tr29/を読んで、最後の\nと一致することを禁じているかどうかはわかりません。 CR | × | LFと表示されています。ここで、 ×は「境界がない(ここで中断しないでください)」という意味です。 したがって、シーケンス\r\n\nブレークする場合、最初の文字と2番目の文字の間に「ブレーク」を配置することは禁止されていますが、3番目の文字の前に「ブレーク」を配置しても問題ありません。 したがって、 \r\n\nを2つの別個の「書記素クラスター」として読み取ります。 IndexOfは完全な書記素クラスターにのみ一致し、クラスターの一部に触れないようにする必要がありますが、部分文字列\nTest見つかるはずです。文字列\n\r\nTest \nTest内の\n\r\nTest

また、ICUやUnicode仕様に依存する他のランタイム/プログラミング言語は、この特定の例でも同じように動作するはずだと言っていますか?

開発者がIndexOfようなものを呼び出すときに意識し、意図を表すために意図的にStringComparisonフラグを提供するのに役立つ方法をさらに検討しています。 あなたが思いついたアイデアも歓迎します。

_(必要な免責事項:私はReSharperを含むいくつかのプロジェクトでJetBrainsで働いています。)_

私は当初、この点を広告のように聞こえないようにここに持ち込みたくありませんでしたが、これは非常に関連性があると思うので、それを行う必要があります。 ReSharperはデフォルトで、 IndexOf呼び出すユーザーコードに対して次の警告を表示します。
image

_(このスレッドに参加する前は、この特定のReSharper診断に気付いていなかったので、この議論をするためだけにここに参加している

したがって、他のすべてのツールでもデフォルトでそのような通知を表示することは非常に良い考えだと思います。あるいは、そのような通知でこの偽のメソッドを完全に非推奨にすることさえできます。

@ForNeVeR

また、Unicode仕様がここで関連している場合でも(これは非常に適切かもしれません!)、unicode.org / reports / tr29を読んだことから、最後の\ nに一致することが禁止されているかどうかはわかりません。 スペックを読んでいると、CR | ×| LF、ここで×は「境界なし(ここでブレークを許可しない)」を意味します。 したがって、シーケンスを中断する場合は、\ r \ n \ n最初の文字と2番目の文字の間に「ブレーク」を配置することだけが禁止されていますが、3番目の文字の前に「ブレーク」を配置しても問題ありません。 それで、私は\ r \ n \ nを2つの別々の「書記素クラスター」として読みました

それは正しいです。 \r\n\nは、 \r\n\n 2つのクラスターになります。

また、IndexOfは完全な書記素クラスターにのみ一致する必要があり、クラスターの一部に触れないようにする必要がある場合でも、文字列\ n \ r \ nTest内に部分文字列\ nTestを見つける必要があります。

それは正しくありません。 \n\r\nTestはパーツに分割されます。 \n\r\n 、およびTest\nTestがこの文字列の一部にならないことは明らかです。 クラスター\r\nをシンボルXに置き換えることを考えてみてください。 これで、ソース文字列は\nXTestになり、 \nTestは含まれません。

また、ICUやUnicode仕様に依存する他のランタイム/プログラミング言語は、この特定の例でも同じように動作するはずだと言っていますか?

デフォルトの照合強度レベルを使用している場合、答えは「はい」です。 ICUは、結果に影響を与える可能性のある強度レベルの変更を許可できます。 たとえば、前述したように、次のようなことを行います。

CultureInfo.CurrentCulture.CompareInfo.IndexOf(actual, expected, CompareOptions.IgnoreSymbols)

強度レベルを変更し、操作でシンボルを無視します(これにより、 \n\rの動作が変更され、その時点で無視されます)

また、純粋なICUネイティブCアプリを作成し、同じケースを実行しました。

void SearchString(const char *target, int32_t targetLength, const char *source, int32_t sourceLength)
{
    static UChar usource[100];
    static UChar utarget[100];

    u_charsToUChars(source, usource, sourceLength);
    u_charsToUChars(target, utarget, targetLength);

    UErrorCode status = U_ZERO_ERROR;
    UStringSearch* pSearcher = usearch_open(utarget, targetLength, usource, sourceLength, "en_US", nullptr, &status);
    if (!U_SUCCESS(status))
    {
        printf("usearch_open failed with %d\n", status);
        return;
    }

    int32_t index = usearch_next(pSearcher, &status);
    if (!U_SUCCESS(status))
    {
        printf("usearch_next failed with %d\n", status);
        return;
    }

    printf("search result = %d\n", index);
    usearch_close(pSearcher);
}


int main()
{
    SearchString("\nT", 2, "\r\nT", 3);
    SearchString("\nT", 2, "\n\nT", 3);
}

このアプリは結果を出力します:

search result = -1
search result = 1

これは、.NETで見られる動作と同じです。

今のところ、この特定の\ r \ n動作の詳細を待つ方が良いと思います。 この特定の検索を実行するときに、IndexOfが「GraphemeCluster BoundaryRules」をどのように使用するか(およびそれを実行する必要があるかどうか)は私にはわかりません。

確かに、クラスタリングは照合操作に影響を与えています。 http://unicode.org/reports/tr29/tr29-7.htmlを見ると、次のように明確に示されています。

Grapheme clusters include, but are not limited to, combining character sequences such as (g + °), digraphs such as Slovak “ch”, and sequences with letter modifiers such as kw.書記素クラスターの境界は照合に重要です, regular-expressions, and counting “character” positions within text. Word boundaries, line boundaries and sentence boundaries do not occur within a grapheme cluster. In this section, the Unicode Standard provides a determination of where the default grapheme boundaries fall in a string of characters. This algorithm can be tailored for specific locales or other customizations, which is what is done in providing contracting characters in collation tailoring tables.

詳細があるかどうかはわかりませんが、 いただきます。

したがって、他のすべてのツールでもデフォルトでそのような通知を表示することは非常に良い考えだと思います。あるいは、そのような通知でこの偽のメソッドを完全に非推奨にすることさえできます。

ありがとう!
これも私たちが考えている方向と同じです。

私自身のために、バージョン間のさまざまなオーバーロードを比較しました。

| 方法| netcoreapp3.1 | net5.0 |
| -------------------------------------------------- --------------- | ----------------- | ---------- |
| actual.Contains(expected) | 本当| 本当|
| actual.IndexOf(expected) | 1475 | -1 |
| actual.Contains(expected, StringComparison.CurrentCulture) | 本当| 誤り|
| actual.IndexOf(expected, StringComparison.CurrentCulture) | 1475 | -1 |
| actual.Contains(expected, StringComparison.Ordinal) | 本当| 本当|
| actual.IndexOf(expected, StringComparison.Ordinal) | 1475 | 1475 |
| actual.Contains(expected, StringComparison.InvariantCulture) | 本当| 誤り|
| actual.IndexOf(expected, StringComparison.InvariantCulture) | 1475 | -1 |

このためのアナライザーを含めてください。

これは、長期的には良好である一方で、.NET5が起動すると大量のチャーンを発生させる変更の1つのように思われます。 したがって、これらのメソッドの動作が.NET5と.NETCore 3.1で異なる場合、.NET 5が、渡されたstringを操作する.NET Standard2.0ライブラリ内で定義されたオブジェクトを呼び出すとどうなりますか。 .NETコールサイトから? 古い動作が使用されますか、それとも新しい動作が使用されますか?

@Aarononthewebの新しい動作。 これは、 netstandard2.0をターゲットとするNUnit3のアサーションから最初に見ました。 アップグレード後、ターゲットフレームワークのみを変更すると、テストが失敗し始めました。

それは素晴らしいことではありません-アップグレードしたい場合、参照している古いライブラリが何をするかを制御することはできません。

単体テストでそれを検出せず、本番環境に移行するアプリはいくつありますか?
.NETチームは、これが引き起こす可能性のある痛みと問題、およびコストを考慮しましたか?

それは素晴らしいことではありません-アップグレードしたい場合、参照している古いライブラリが何をするかを制御することはできません。

素敵な罠!
奇妙なバグを狩って幸せな時間を無駄にします🎉
しかし、なぜInvariantGlobalizationがこの問題を解決しないのでしょうか。

このためのアナライザーを含めてください。

ええ。 そして、F#のサポートを忘れないでください。

単体テストでそれを検出しないアプリの数

ゼロ-単体テストは、.NETBCL自体のような外部ライブラリ/フレームワークをテストすることを意図していないためです。

私の見解では、この動作変更のモードを制御できるアセンブリレベルの属性が必要です。 少なくとも、アセンブリごとのレベルでオプトイン/オプトアウトできます。 これは、.NET標準の問題もなくなることを意味します。

それは素晴らしいことではありません-アップグレードしたい場合、参照している古いライブラリが何をするかを制御することはできません。

なぜあなたがそれをコントロールできないのか分かりません。 すべての文字列比較は、ICUまたはNLSのいずれかを使用しています。 必要に応じて、互換スイッチを使用しそうすると、すべてのライブラリが以前の動作に戻ります。

グローバリゼーションデータが長期にわたって安定しているとは限りません。 安定したグローバリゼーションデータに依存している人々を壊すことを恐れていないことをWindowsチームから聞いてください。 グローバリゼーション関数はブラックボックスである必要があります。 ライブラリ(特に.NET Standardを対象とするライブラリ)がこのような実装の詳細に依存していると言うのは意味がないと思います。

.NETグローバリゼーション関数がWindowsとLinuxで異なる結果を返すことについて多くの人が不満を言っていると確信しています(そしておそらくもっと多くの人がまだ気づいていません)。 Windowsと他のプラットフォームの間で動作を統一することをお勧めします。正しいコードは、グローバリゼーションデータが不変であることに依存してはなりません。

StringComparison.Ordinalもデフォルトの比較戦略にするために、重大な変更を加えることを検討しますか? グローバリゼーションは非常に不安定であるため、少なくともデフォルトの実装では代わりに安定したアルゴリズムを使用することは理にかなっています。 StringComparisonを渡さずにstring.Equals(...)string.Contains(...)などを使用する人の99.9%が、に関連する奇妙な癖を処理するという明確な意図を持ってそれを行っていないことは間違いありません。ロケール。

編集:私の質問はすでに回答済みだと思います:

実際、Silverlightのリリース中は、以前に序数の動作をデフォルトとして作成しようとしましたが、ここで報告されているよりもはるかに多くの問題が発生しました。 開発者がIndexOfのようなものを呼び出すときに意識し、意図を表すために意図的にStringComparisonフラグを提供するのに役立つ方法をさらに検討しています。 あなたが思いついたアイデアも歓迎します。

必要に応じて、互換スイッチを使用してICUをオプトアウトできます。そうすると、すべてのライブラリが以前の動作に戻ります。

私はアプリケーションではなく、生活のためのライブラリを作成しています。 これを処理するコンパイル時の方法が欲しいです。

私たちが行う作業のほとんどはInvariantCulture 。これは、私の以前の理解によれば、設計上不変であると想定されています。 IndexOfの動作は、そのような状況でも.NET5.0と.NETCore3.1で異なるようです。

アナライザーは既存のプロジェクトにどのように役立ちますか?

@petarrepacもC#のみです。

@isaacabrahamとVBも;)

これを処理するコンパイル時の方法が欲しいです。

@Aarononthewebには、これを処理するコンパイル時の方法があります(アプリをコンパイルするとき)。 これをプロジェクトに追加できます。

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
</ItemGroup>

編集:これはライブラリを消費するアプリ専用ですが、残念ながら、ライブラリを作成するときにこれを制御することはできません。

長期的には、WindowsチームはICUへの移行を推進しているため、ある時点でICUがグローバリゼーションのストーリーになり、OSライブラリの単なるラッパーになります。

.NET 5が、.NETコールサイトから渡された文字列を操作する.NET Standard 2.0ライブラリ内で定義されたオブジェクトを呼び出すとどうなりますか? 古い動作が使用されますか、それとも新しい動作が使用されますか?

新しい動作が使用されます。これは、ランタイムに依存し、.NETStandardはランタイムが実装するための単なる標準であるためです。 ただし、これによりUnixとWindowsの間でプラットフォームの一貫性がもたらされることに注意してください。Unixで懸念されている同じライブラリを実行すると、 ICUがサポートされるため、 ICU結果が得られます。 Unixのライブラリ。

@reflectronicは、彼のすべての点で正しいhttps://github.com/dotnet/runtime/issues/43736#issuecomment-716681586です。

https://github.com/dotnet/runtime/issues/43736#issuecomment -716527590で言及されている@jbogardの結果にコメントするには、WindowsとICUの言語動作を比較することで結果を要約できます。 ちなみに、ICUは現在Windows上の多くのアプリケーションで使用されており、使用量の増加が見込まれます。 また、これらの結果は、.NET Core3.1以下のLinuxを除外しています。 これは、.NET5.0とLinux上の以前のバージョンとの間の一貫性を示します。

以前は機能していたライブラリに関するポイントが壊れますが、そのようなライブラリはLinuxですでに壊れているため、これは完全には当てはまりません。

StringComparison.Ordinalをデフォルトの比較戦略にするために、重大な変更を加えることを検討しますか?

先ほども申し上げましたが、苦情の大きさは非常に大きく、適用できませんでした。 開発者が照合APIを呼び出すときに文字列比較フラグを指定することを意識できるようにする方法を検討しています。

私はアプリケーションではなく、生活のためのライブラリを作成しています。 これを処理するコンパイル時の方法が欲しいです。

はい、一部のアナライザーはそのような場合に役立ちます。 通常、照合API呼び出しを調べて、順序または言語操作を使用する意図を示していない呼び出しを調べます。

アナライザーは既存のプロジェクトにどのように役立ちますか?

アナライザーはコードをスキャンし、フラグを渡さない照合APIの呼び出しを検出すると、そのような呼び出しを調べて、検出された問題があれば修正するのに役立ちます。

これもC#のみです。

変更は.NETランタイム内にあり、グローバルであり、C#に制限されていない必要があります。

@tarekgh C#アナライザーはVBまたはF#コードベースでどのように表示されますか?

私たちが行う作業のほとんどはInvariantCulture 。これは、私の以前の理解によれば、設計上不変であると想定されています。

重要なことに、この変更の前は、クロスプラットフォームコードを実際にこれに依存することは不可能でした。 NLSとICUがどのように動作するかは、不変のカルチャを使用している場合でも、常に同じであるとは限りません(この問題で証明されています)。 @tarekghが言ったように、このコードは

これは驚きかもしれませんが、他の多くのライブラリ作成者が何年にもわたって行ってきたと確信しているように、ユーザーレポートの結果として、プラットフォームの違いに関連する数十のバグを最終的に見つけて修正しました。

.NET 5が未知の未知数の新しい作物を導入し、ライブラリだけでなくダウンストリームの依存関係についてもそれらの修正を再検討するという見通しに私は興奮していません。 これは私たちにとって大きな経済的コストであり、ユーザーの生産性を新たに向上させることはありません。 MSFTの誰かが、この変更を行う際のコスト/メリットの議論でその考慮を払う必要があります。

編集:たとえば、私はすでに技術的なメリットを享受しています-はい、ありがとうございます。 コストではなく、この変更を行うことによる非自明な経済的利益の販売を支援してください。 この問題がどのようなネズミの巣であるかを考えると、ユーザーが飛躍して.NET 5にアップグレードする必要があるのはなぜですか?

@tarekgh C#アナライザーはVBまたはF#コードベースでどのように表示されますか?

単一のアナライザーでC#とVBをカバーできますが(可能な限りアナライザーを言語に依存しないように努めています)、現時点ではF#のアナライザーカバレッジを取得できません。

@Aaronontheweb文化的機能を使用していて、変更されないと想定している人は、このICUの変更を行わなかったとしても、すでに壊れています。 Windowsチームのブログhttps://docs.microsoft.com/en-us/archive/blogs/shawnste/locale-culture-data-churnを見てください。このブログでは、改善のためにNLSの動作も変更されています。 したがって、ここでの問題は、アプリ/ライブラリの観点から間違った仮定を捕らえること以上にICUに移行することではありません。 5.0へのアップグレードは、他の以前のバージョンへのアップグレードと同じです。 アプリは多くの新しいクールな機能を取得し、リリース間のいくつかの重大な変更がある可能性があるため、アプリをテストする必要があります。 グローバリゼーションはOSとOSのバージョン間でいつでも変更される可能性があると常に言っているので、グローバリゼーションの動作の変更が実際に壊れているとは考えていません。 前に示したように、NLSを引き続き使用して5.0にアップグレードすることを選択する構成スイッチがあります。 それはICUをアップグレード決定の実際の要因ではないようにします。 ICUを使用すると、アプリはOS間で一貫性を高める機会が得られ、アプリローカルICUを使用することにした場合は、グローバリゼーションの動作をより細かく制御することもできます。 以前よりもはるかに多くの制御をアプリに提供しています。

関連: https

(この問題は、 IndexOf _それ自体_を追跡しません。むしろ、 Compareルーチンがデフォルトでカルチャ対応の比較プログラムに設定された場合の意図しない結果について説明します。)

アナライザーは既存のプロジェクトにどのように役立ちますか?

アナライザーはコードをスキャンし、フラグを渡さない照合APIの呼び出しを検出すると、そのような呼び出しを調べて、検出された問題があれば修正するのに役立ちます。

アナライザーをcsprojに追加する必要があると思います。
これは自動的には発生しません。 そのため、既存のプロジェクトの多くは、これらのアナライザーなしで.NET5に移行されます。
さらに、すでに述べたように、F#プロジェクトには役立ちません。

@jeffhandleyありがとう、それは私がすでに理解したことを確認します。 したがって、考えられる「回避策」はF#ユーザー(小さな市場ですが、.NETの第一級市民としてMSによって完全にサポートされている市場)には役立たないことを認識することが重要です。 これが何を意味するのかわかりません:

変更は.NETランタイム内にあり、グローバルであり、C#に制限されていない必要があります。

これが何を意味するのかわかりません:
変更は.NETランタイム内にあり、グローバルであり、C#に制限されていない必要があります。

つまり、C#だけでなく、.NETランタイムを使用するすべての言語が影響を受けるということです。

特に現在の行動を変える計画がある場合は、箱から出して新しい世界でこれらの落とし穴を明らかにするためのアナライザーが必要であるという私の意見をもう一度強く表明します。

私はそうすることの技術的なメリットを完全に理解しており、変更を加えないことを示唆しているわけではありません(長期的にはこれが正しい動きのようです)。 また、ベストプラクティスとしてまだ文書化されていないと言っているわけでもありません。 私が言っているのは、これが.NET 5に移行しようとしている開発者にとって、大きくて赤く点滅するエラーである必要があるということです。

現在、 @ meziantouのRoslynAnalyzer Libraryをhttps

この特定のケースでは、これはMA0074をスローし

image

これは本当に箱から出しておく必要があると言われていますが、私はこのRoslynの問題をここで開きました: https

@tarekgh明確にしてくれてありがとう。 私の最初のポイントは、すべての.NETユーザーに有効なソリューションを探しているのであれば、アナライザーはここでは答えではないということでした。

開発者がIndexOfのようなものを呼び出すときに意識し、意図を表すために意図的にStringComparisonフラグを提供するのに役立つ方法をさらに検討しています。 あなたが思いついたアイデアも歓迎します。

[Obsolete]属性を使用して)古いメソッドを非推奨にするのはどうですか?

APIサーフェスが同じであるが動作が変わる場合、.NET標準の互換性はどうなりますか?

影響が十分に文書化されている限り、書記素クラスターを尊重するための変更は私を悩ませません。 文字列メソッドのファミリーの密接に関連するメンバーが互いに一貫性のない動作をする原因となる変更。

文字、書記素クラスター、またはロケールのあいまいさに関係なく、非公式の文字列の変更を行っている人は、str.Contains(whatever)が成功した場合、str.IndexOf(whatever)の結果を検査する必要がないことを前提としています。 )そこにあると言われたので、見つけることができます。 デフォルトはメソッド間により

このような矛盾は、専門家だけがうまく使用できる言語を生み出し、コードキャンプから出てくる人々を遠ざけます。 この方法でエントリーするためにバーを上げないでください。

@lupestroに同意します。 メソッドの動作の不一致は非常に懸念されます。 長年の方法で異なる動作と一貫性のない動作の両方を行う場合は、多くの悲しみがあります。 人々はこれに遭遇し、APIに裏切られたと感じ、他にどのような時限爆弾が爆発するのを待っているのか疑問に思うでしょう。 多くの場合、.NETの採用者は、この種の問題についてC#を書き留めます。 ロケールを受け入れないオーバーロードを削除するか、メソッドのデフォルトロケールを正規化する必要があるようです。 すでにCompareとCompareOrdinalがあり、おそらく(Last)IndexOf(Any)と(Last)IndexOf(Any)Ordinalが必要です。 私はその解決策が好きではありませんが、少なくともそれは現在存在するものと一致するでしょう。 おそらく、文字列での通常の使用法のアイデアは減価償却する必要があります。 高速または右のどちらかを選択する必要がある場合は、毎回「右」を選択します。 一貫性のない、直感的でない行動は非常に苛立たしいものです。

この問題はすでに解決されているので、.NET5.0で進めることがすでに決定されていると思います。 私はこれが難しいことを知っています、そして文化(時間のような)情報はあらゆる種類の非技術的な理由で変わることができます。 開発者はこれを認識する必要がありますが、自己整合性を保つためにAPIに依存する必要もあります。 @aolszowkaが指摘しているように、問題を示す警告(5.0)が少なくともあるはずです...そしてさらに重要なことに、それが問題である理由。 前進することは重要であり、時にはそれはあなたが古い行動/仮定を「破る」必要があることを意味します。 これは、新しい不整合を導入する必要があることを意味するものではありません。 この変更は、コードだけでなく期待も破ります。 メソッドの一貫性を保つことができない場合は、直感的でないエラーがコードを爆破する可能性があるだけでなく、CultureInfoを明示的に強制することをお勧めします(拡張メソッドを介して対処できます)。ストレスの多い開発サイクル、または顧客のインストールで最悪。

TLDR:変更が必要なものを変更しますが、変更するためにAPIの一貫性を失わないようにします。 あなたがそれを壊そうとしているならば、それをより良いものと取り替えてください。

私は何年も.NETを使用しており、これらの関数を使用するときは常にデフォルトでInvariantCultureになります。 英語以外の言語に関しては、他の言語固有の文字のエイリアスとして機能する文字ペアと、CurrentCultureをデフォルトとして比較するときにこれらのペアをチェックするための追加の作業を常に認識しています。 これは、たとえば、ブラウザーから送信されたユーザーの優先言語に基づいてスレッドのCurrentCultureを設定するASP.NETコードを作成するときに私を悩ませました。英語を使用していないユーザーを比較すると、特にコードが微妙に壊れます。文字列にユーザーが入力した(言語)テキストと通常のテキストが混在している場合。

このUnicode書記素クラスターの動作は、私にとっては新しいものです。通常のように不変のオーバーロードを使用した場合でも、改行とキャリッジリターンの通常の動作を期待していたからです。 より多くの仕事をし、専門家の知識を必要とする行動は、技術的な正当性に関係なく、オプトイン行動であるべきだと私には思えます。 おそらくその船はずっと前に出航しましたが、_この重大な変更_は、あいまいなブログを読まなくても、たとえば言語の変更と同じくらい透過的に行う必要があります。 私の同僚は、新しいC#9.0の機能にほとんど気づいていません。ましてや、今日書いているコードに影響を与える可能性のある難解なICUルールは、いつか.NET 5(または、おそらく.NET 6または7)に移植されてコンパイルされる可能性があります。

古い方法を廃止することは、私たちが検討していることの1つです。 私は昨夜提案の草案を完成させ、内部レビューのためにそれを探し回っています。数時間以内に新しい問題としてここに投稿します。

ドラフトはhttps://github.com/dotnet/runtime/issues/43956に投稿されてい

バグを報告している場合は、新しい問題を提出し、その新しい問題を使用してバグを説明してください。

この特定の問題( "\r\n""\n" )についてコメントがある場合は、このスレッドで返信を続けてください。 ありがとう!

@GrabYourPitchforksのドキュメントに記載されているアプローチを検討しながら再開します。

私たちはあなたの言うことを聞いています-ここには多くの明確なフィードバックがあります-私たちは正しい道を見つけるために取り組んでおり、この問題を更新し続けます。

影響が十分に文書化されている限り、書記素クラスターを尊重するための変更は私を悩ませません。 文字列メソッドのファミリーの密接に関連するメンバーが互いに一貫性のない動作をする原因となる変更。

文字、書記素クラスター、またはロケールのあいまいさに関係なく、非公式の文字列の変更を行っている人は、str.Contains(whatever)が成功した場合、str.IndexOf(whatever)の結果を検査する必要がないことを前提としています。 )そこにあると言われたので、見つけることができます。 デフォルトは_メソッド間で同じように動作するため_、それらを使用するためにすべての微妙な点を研究する必要がないため、彼らが気にしない2番目のパラメータがデフォルトであるかどうかは関係ありません。

このような矛盾は、専門家だけがうまく使用できる言語を生み出し、コードキャンプから出てくる人々を遠ざけます。 この方法でエントリーするためにバーを上げないでください。

はい、これは完全に私の懸念を表しています。 典型的な中国の開発者として、アプリケーションコードで文字列関連のメソッドを呼び出すときにStringComparisonまたはCultureInfo明示的に配置することはめったになく、それは機能します。 IndexOfContains間で異なる動作を期待することは絶対にありません!
.net 5.0
image
.netコア3.1
image
。ネットフレームワーク
image

@lupestroに同意します。 メソッドの動作の不一致は非常に懸念されます。 長年の方法で異なる動作と一貫性のない動作の両方を行う場合は、多くの悲しみがあります。

おそらくここで重要な点は、2つの方法が常に一貫しIndexOfは常に現在のカルチャ比較を使用し、 Containsは常に序数比較を使用しています。 付与された.NET5.0は、さらに不整合を追加します。 しかし、ここでの間違いは、この不整合を許容する元のAPI設計にありました。

私が物事を正しくフォローしている場合、IndexOfは常に序数比較を使用し、Containsは常に現在のカルチャ比較を使用しています。 付与された.NET5.0は、さらに不整合を追加します。 しかし、ここでの間違いは、この不整合を許容する元のAPI設計にありました。

それは正しいですが、その逆です。 IndexOf(string)は現在のカルチャを使用し、 IndexOf(char)は序数を使用し、 Containsは序数を使用します。

最近他の人がほのめかしたIndexOfContains違いについて簡単に説明します。

IndexOf(string)は常に_CurrentCulture_比較を想定しており、 Contains(string)は常に_Ordinal_比較を想定しています。 この不一致は、.NETFrameworkにさかのぼって存在していました。 これは、.NET 5で導入された新しい不一致ではありません。たとえば、.NET Framework(WindowsのNLS機能を使用)では、言語比較プログラムでは、合字「æ」と2文字の文字列「ae」が同等に比較されます。 これにより、次の不一致が発生します。

// Sample on .NET Framework, showing Contains & IndexOf returning inconsistent results
Console.WriteLine("encyclopædia".Contains("ae")); // prints 'False'
Console.WriteLine("encyclopædie".IndexOf("ae")); // prints '8' (my machine is set to en-US)

この不一致は10年以上前から存在しています。 それ文書化されており、それに関するガイダンスがあります。 それはミスデザインですか? おそらく。 https://github.com/dotnet/runtime/issues/43956で、エコシステムをより健康的にする方法について話し合ってい

この特定の問題について、私たちが本当に自問しているのは、「矛盾が永遠に存在していることを考えると、これら2つの方法は、より大きな生態系に害を及ぼす前に、実際にはどれだけ離れているのでしょうか?」 そのしきい値をどこに置くべきかをまだ定義しようとしていると思います。 このようなレポートは、人々が実際にこれらのAPIを使用していることや、顧客が自分の行動に関してどのような期待を持っているかについての洞察を提供するため、_非常に_役に立ちます。 フレームワークの管理者として、技術文書だけでなく、実際のアプリがこれらのAPIを使用する方法も考慮する必要があります。

このコメントは、特定の観点を擁護することを意図したものではありません。 私の意図は、私が見たいくつかの誤解を明確にし、問題をどのように組み立てたかを説明するのを助けることです。

InvariantCultureが指定されている場合でも、 \nがICUバージョンで一致しないのは正しい動作ですか?

image
image

たぶん、gitとそのデフォルト設定(autocrlf = true)を使用すると、次のコードはLinuxでは5、Windowsでは-1を表示しますか?

using System;

var s = @"hello
world";
Console.WriteLine(s.IndexOf("\n", StringComparison.InvariantCulture));

@ufcppはい、このスレッドで前述したように、ICUごとに予想される動作です。 2つの文字<CR><LF>が互いに隣接して出現する場合、言語学的な目的では壊れない単位と見なされます。 言語比較器(_InvariantCulture_など)を使用して<LF>を検索すると、この壊れないユニットが分割されるため、一致するものは生成されません。

更新を皆さんと共有したいと思います。5.0GAのデフォルトとしてICUを維持することにしました。 https://github.com/dotnet/runtime/issues/43956で追跡されている、序列が意図されたときに誤って言語比較を使用することの落とし穴を改善することを検討し

これは非常に難しい決定であり、エコシステムへの互換性の影響と、プラットフォーム間の標準化の推進力を比較検討する必要がありました。

現在の緩和策が不十分であると判断された場合は、この問題を開いたままにして、サービスにおける\r\n問題のさらなる緩和策を検討します。

また、ICUの切り替えの結果として発生した問題については、動作が既知の原因である可能性があるとしても、「設計による」という意味ではなく、引き続き報告することをお勧めします。 引き続き違いを調査し、根本原因を理解し、それらに対処するためにICUまたは.NETに変更を加える必要があるかどうかを判断します。

StringComparisonを常に指定するためのアナライザールールがあります。

https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307

更新を皆さんと共有したいと思います。5.0GAのデフォルトとしてICUを維持することにしました。 #43956で追跡されている、序列が意図されたときに誤って言語比較を使用することの落とし穴を改善することを検討します。 また、この問題の影響を受けていると特定したライブラリのいくつかにも連絡します。 今後数日で、問題のあるコードをより適切に特定し、この問題を回避するために修正するのに役立つ、今後の5.0リリースに付随するドキュメントをさらに共有する予定です。

これは非常に難しい決定であり、エコシステムへの互換性の影響と、プラットフォーム間の標準化の推進力を比較検討する必要がありました。

現在の緩和策が不十分であると判断された場合は、この問題を開いたままにして、サービスにおける\r\n問題のさらなる緩和策を検討します。

また、ICUの切り替えの結果として発生した問題については、動作が既知の原因である可能性があるとしても、「設計による」という意味ではなく、引き続き報告することをお勧めします。 引き続き違いを調査し、根本原因を理解し、それらに対処するためにICUまたは.NETに変更を加える必要があるかどうかを判断します。

自分で制御できない.NET標準の依存関係を引き続き使用できるかどうかを知りたいのですが。

できないのではないかと思います。 人々が.NETStandard 2.2に移行することを確認するのはどうですか? APIを変更しますか?

期待どおりの動作が得られるという事実を知ることができるようにするためです。

すでにかなりの問題を抱えている現在のエコシステムを壊さないようにする方法が他にあるかどうかはわかりません。

私は間違っていると証明されてうれしいです、偏見を持ってそうしてください-それは私の心を和らげるでしょう:)

@rcollina

自分で制御できない.NET標準の依存関係を引き続き使用できるかどうかを知りたいのですが。

.Net標準ライブラリは、通常、クロスプラットフォームであると想定されています。 また、一部のライブラリが今日のUnix上の.Net Core 3(ICUを使用)で正しく機能する場合、ほぼ確実にWindows上の.Net 5(ICUも使用)でも機能します。

.NET標準2.2

.Net Standard vNextは事実上存在しますが、「。Net5.0」と呼ばれています。 (つまり、ライブラリを作成していて、古いフレームワークのサポートを気にしない場合は、今日、.Net Standard 2.1をターゲットにします。1か月以内に、代わりに.Net 5.0をターゲットにします。)

@svickわかりました。 .NETStandardがどのように機能するかはすでに理解していると思います。 .NET5が新しい.NET標準であることを理解しています。

申し訳ありませんが、IndexOfとContainsの間の既存の動作の不一致に依存する.NET Standard2.1ライブラリを参照するとどうなるかまだわかりません。

ここで変わっているのは、帯域外のICUとNLSです。 この変更により、すでに発生していた不一致が広がり、期待が裏切られます。
この情報をライブラリにエンコードするものは何もありません。

私はすべての意味を理解しているとは思いませんが、新しい通常へのシームレスなオンボーディングパスがなければ、私たちが「技術的に正しい」という感覚を振り払うことはできません。 これは切実に必要です。

他の誰かが言ったように、ほとんどの人は新しい言語機能にさえ気づいていません。ましてや、私たちの最高のコミュニティメンバーによってランダムに発見されたこのような地震の変化は言うまでもありません。 これに耐えられる可能性は何ですか?

自分で制御できない.NET標準の依存関係を引き続き使用できるかどうかを知りたいのですが。

ここで変わっているのは、帯域外のICUとNLSです。 この変更により、すでに発生していた不一致が広がり、期待が裏切られます。

いいえ、そうではありません。 ここでは、ICUがUnixで_常に_使用されていることを強調することはできません。 .NET Standardライブラリは設計上移植可能であると想定されており、以前はLinux .NET Core3.xで機能していたものはすべて.NET5でも機能します。

私たちが行う作業のほとんどはInvariantCultureです。これは、私の以前の理解によれば、設計上不変であると想定されています。

違います。 InvariantCultureは、ユーザーの言語設定を無視することのみを想定しています。 それでも、Unicode仕様やグローバリゼーションライブラリなどの更新によって変更される可能性があります。

.NETチームは、これが引き起こす可能性のある痛みと問題、およびコストを考慮しましたか?

このような発言は私を終わらせません。 この変更で突然壊れたコードは、そもそも正しくありませんでした。 .NETチームが誤った、または実装の詳細に依存するユーザーコードの動作を保持する必要がある場合、プラットフォームはどのように前進することになっていますか? 彼らが互換性スイッチを提供しなかったわけではありません。 .NETCoreが.NETFrameworkからスピンオフした理由の大部分は、サイドバイサイドインストールやアプリローカルランタイム展開などの機能を通じてこの問題を解決することでした。 このために.NET5に移行できない場合は、.NET5に移行しないでください。

.NET 5が未知の未知数の新しい作物を導入し、ライブラリだけでなくダウンストリームの依存関係についてもそれらの修正を再検討するという見通しに私は興奮していません。

あなたが主張するようにすべてのプラットフォームの違いのバグを潰したなら、あなたは心配する必要は何もないはずです。

.NETチームは、これが引き起こす可能性のある痛みと問題、およびコストを考慮しましたか?

このような発言は私を終わらせません。

何百万ものプロジェクトが.NETで実行されており、文字列操作は非常に頻繁な操作です。
.NETチームがこれを修正/変更するのにかかる労力は、.NET5 / 6に移行されるすべての既存のコードを検証するために必要な労力と比較してごくわずかです。

したがって、これに対処するための「計画」について質問するのはかなり公正です。
何か計画はありますか?
この変更の影響は推定されましたか?
全プロジェクトの0.001%ですか? 75%ですか?
私たちが知らない他の同様の変更は何ですか?

たぶん、これはほんの少数のプロジェクトに影響を及ぼします。
しかし、それは推定されましたか?

ところで、十分な理由があれば、私はすべて変更を壊すためです。 ただし、リスクがそれほど高くない移行パスも必要です。

@petarrepac誤解しないでください、私はそれを理解しています。 しかし、このスレッドで何度も指摘されているように:

  1. 計画があり、ランタイム構成スイッチを提供することです。
  2. 壊れていると主張されている動作は、Windows以外のすべてのプラットフォームでの.NETの既存の動作です。
  3. これは、序数が意図された場所で文化に敏感な操作を実行するコードにのみ影響するはずです。

最後の2つのポイントを考えると、これがプロジェクトのかなり小さな割合に影響を与えると想定することはおそらく合理的です。

100%これについて質問するのは公正ですが、私が引用したようなコメントを書く人々は、変更の背後にある全体像を理解しようとする前に、考慮が入れられて書かれていないと思い込んでいることがよくあります。

こんにちは皆さん。 この問題が発生したときに行ったアクションの概要と、最後に、Windows 10 May 2019Update以降のデフォルトをICUfor .NET5.0に維持することにした理由を簡単に説明したいと思います。

問題が開かれたとき、私たちは、お客様が間に矛盾を与えられて、これは持っていた可能性があることの潜在的な影響や痛みについてのいくつかの内部の議論を開始したContains(string)であるOrdinalIndexOf(string)はカルチャに対応し、さらに他のAPIは文字列を操作する場合はデフォルトでカルチャに対応しますが、 Span<char>またはReadOnlySpan<char>操作する場合はOrdinalなります。 そのため、この問題について話し合った後、影響を受ける可能性のあるNuGetパッケージの分析を開始し、データを収集して明確な状況を把握しました。 これが私たちの発見でした:

  • 「\ n」は、IndexOf、LastIndexOf、EndsWith、StartsWith、Compare、およびCompareToに渡される「最も使用される文字列リテラル」の#30です。
  • String.EndsWithへの呼び出しサイトの1%は、\ nで始まる検索文字列を使用しています。 テスト対象の文字列に「Windowsスタイルの行末」が含まれているこれらのコールサイトはいずれも壊れます。
  • NuGet.orgでホストされている2040のパッケージIDがあり、バージョンにはリスクのあるコールサイトを持つアセンブリが含まれています。
  • これらのコールサイトの大部分はEndsWithとIndexOfに対するものであり、これは、このパターンが単純な改行アルゴリズムに頻繁に使用されるという仮説と一致しています。

リスクのあるコールサイトがあったこれらの2040パッケージのうち、一部のバージョンの.NETStandardまたは.NETCoreをサポートしているのは539のみであるため、NuGet.orgにリストされているパッケージの0.54%のみが中断にさらされる可能性があります。

影響を受ける可能性のある539個のパッケージIDのリストにあるパッケージを調べて、それらへの実際の影響を把握しました。 トップ70(ダウンロード数による)を調べたところ、最新バージョンでは20はパターンを公開していませんでした。パターンを公開したものから、許可ライセンスを持っていた32のみを確認できました。

  • 14はバグの対象ではありませんでした
  • 13が壊れた可能性がある
  • 5つは不確実でした(多様な改行パターンまたは他の緩和策の防御的なコーディングによる中断の明確な兆候はありませんでした)。

つまり、ダウンロードによる上位70のパッケージのうち、影響を受ける可能性があるのは18%のみでした。

これらのパーセンテージは積み重ねられており、NuGet.orgのパッケージの総数である229,536に対してではありません。 したがって、NuGet.orgでパッケージの総数とダウンロードの総数を使用した場合、影響を受ける可能性のあるパッケージは229,536のうち、0.24%で539になります。

ライブラリを分析することは私たちにとって素晴らしいことですが、nugetはそこにあるC#コードのごく一部にすぎません。 また、誰かがコードを所有している場合でも、a)バグを追跡するのは簡単ではなく、b)実際にはソースを持っていない可能性があります。

ただし、これは、動作の非常に顕著な変化である可能性がある一方で、Windowsの行末を含む可能性のある入力(それほど一般的ではない可能性があります)を読み取るときにUnixですでに発生した中断であると結論付けるのに適したデータソースでした。

.NETCoreと.NET5 +では、OS間の一貫性を目指して努力しており、この変更の影響を考えると、それは正しいことのように感じました。 私たちは互換性を重視しているため、従来の動作に戻れるように互換性のあるランタイムスイッチを提供しています。

また、Unixでの動作がすでに異なっていることを考えると、検査できるパッケージからの結論は、OS間の潜在的な中断を軽減するために、この問題に対する多くの防御的なプログラミングを見ました。

これに加えて、グローバリゼーションはOS全体の薄いラッパーであるためいつでも変更される可能性があるため、サポートするすべてのOSで同じラッパーであることが現時点では正しいと感じました。

この一環として、実用的な例、roslynアナライザーのルール、および影響を受けるコードがこれをどのように軽減できるかを使用して、ドキュメントを改善しました。

https://github.com/dotnet/runtime/issues/43956で説明されているように、常により良い場所に移動し、.NET 6のこのエクスペリエンスを改善し続けるため、貴重なフィードバックをありがとうございます

UnixとWindowsの行末の違いが原因で発生する可能性のある問題を理解しているため、この問題を未解決のままにして、.NET 5.0の\r\nケースを軽減するための可能な方法を調査します。 .xは、サービスリリースの一部である必要があります。

charとstringにも違いがあります。

Console.WriteLine("com/test/test/test/a/b/ʹ$ʹ".IndexOf("$"));
Console.WriteLine("com/test/test/test/a/b/ʹ$ʹ".IndexOf('$'));
-1
24

@mattleibowは、文字検索を使用すると、通常の検索を実行します。 This method performs an ordinal (culture-insensitive) searchと記載されているドキュメントhttps://docs.microsoft.com/en-us/dotnet/api/system.string.indexof?view=net-5.0#System_String_IndexOf_System_Char_ 。 序数オプションを使用して文字列検索を実行すると、文字と同じ結果が得られます。

C# Console.WriteLine("com/test/test/test/a/b/ʹ$ʹ".IndexOf("$", StringComparison.Ordinal));

〜これは、と思われCA1307は上の唯一のトリガーindexof(char)ではなくindexof(string)stringバージョンのルールはありますか? charのデフォルトは自動的に序数を使用し、破壊的な変更は実際にはこれに影響しないため、これはより重要なようですが、 stringが変更され、動作を復元するには序数を指定する必要があります場合によっては。〜

indexof(string)どのように検出しますか?〜

それを見つけました、それはルールCA1310です。 私たちのドキュメントはhttps://docs.microsoft.com/en-us/dotnet/standard/globalization-localization/globalization-icu#use-nls-instead-of-icuに対して間違っており、この特定のバリエーションについては言及していません。 それらのドキュメントを更新します。

このページは役に立ちましたか?
0 / 5 - 0 評価