1. ホーム
  2. c#

[解決済み] C# SwitchステートメントでIgnoreCaseを使用する方法

2023-01-05 03:12:32

質問

switch-case ステートメントで switch 内のオブジェクトが string の場合、ignoreCase 比較は可能でしょうか。

例えばこんなのがあります。

string s = "house";
switch (s)
{
  case "houSe": s = "window";
}

ウィル s は、値 "window" を取得するのでしょうか?switch-caseステートメントをオーバーライドして、ignoreCaseを使用して文字列を比較するようにするにはどうすればよいですか?

どのように解決するのですか?

ご存知のように、2 つの文字列を小文字にして比較することは、大文字小文字を無視した比較を行うこととは異なります。これには多くの理由があります。たとえば、Unicode 標準では、発音区別符号を含むテキストを複数の方法でエンコードすることができます。一部の文字は、基本文字と発音区分符号の両方を 1 つのコードポイントに含んでいます。これらの文字は、基本文字の後に結合された発音区分け文字として表現されることもあります。これらの2つの表現はすべての目的のために等しく、.NET Frameworkの文化認識文字列比較は、CurrentCultureまたはInvariantCulture(IgnoreCase付きまたはなし)のいずれかで、それらを等しいものとして正しく識別します。一方、序数比較では、誤ってそれらを非同等と見なします。

残念ながら switch は序数比較以外のことは行いません。序数比較は、厳密に定義されたコードを持つ ASCII ファイルを解析するような特定の種類のアプリケーションでは問題ありませんが、序数文字列比較は他のほとんどの用途で間違っています。

正しい動作を得るために私が過去に行ったことは、単に私自身の switch 文をモックアップすることでした。これを行うには多くの方法があります。1 つの方法は List<T> を作成し、ケース文字列とデリゲートのペアを作成することです。このリストは、適切な文字列比較で検索することができます。一致するものが見つかると、関連するデリゲートが呼び出されるかもしれません。

もう一つの方法は、明らかな連鎖である if ステートメントを連鎖させることです。これは通常、構造が非常に規則的であるため、それほど悪いものではないことがわかります。

これの素晴らしいところは、文字列と比較するときに独自のスイッチ機能をモック化しても、パフォーマンス上のペナルティがないことです。システムは整数でできるような O(1) のジャンプテーブルを作ろうとしないので、いずれにせよ各文字列を一度に比較することになります。

比較するケースが多く、パフォーマンスが問題になる場合は List<T> オプションはソートされた辞書やハッシュテーブルに置き換えることができます。そうすれば、パフォーマンスは潜在的にswitch文オプションと同等かそれ以上になるかもしれません。

デリゲートリストの例です。

delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
    foreach (var switchOption in customSwitchList)
        if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
        {
            switchOption.Value.Invoke();
            return;
        }
    defaultSwitchDestination.Invoke();
}

もちろん、CustomSwitchDestinationデリゲートに標準的なパラメータと、場合によっては戻り値の型を追加したいと思うことでしょう。そして、より良い名前を付けたいと思うことでしょう!

各ケースの動作が、異なるパラメータが必要であるなど、この方法でのデリゲート呼び出しに従わない場合、連鎖的な if ステートメントを連鎖させることになります。私も何度かやったことがあります。

    if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "window";
    }
    else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "really big window";
    }
    else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "broken window";
    }