C#で文字列にSQLのIN句のようなメソッドを追加する

SQLにあるIN句をC#の文字列に適用し、リストに格納された文字列がある文字列に一致するかどうかを判定する処理をstringに追加したいと思います。

例えば"ABC123"という文字列の中に"AB", "12"という文字が含まれているかという処理は以下のように書けば判定できます。

string str = "ABC123";

// ★判定方法(1)
if(str == "AB" || str == "12")
{
    // 見つかった
}
else
{
    // 見つからなかった
}

// ★判定方法(2)
List<string> keys = new List<string>()
{
    "AB", "12"
};
foreach(string item in keys)
{
    if(str == item)
    {
        // みつかった
    }
}

(1)の場合、対象が個数が増えていくと重複したコードが増えるし(2)だと見つからないときに何かしら追加が必要です。

どうせなら1行でかけたらいいのに…という実装アイデアです。

コード例

早速ですがコード例です。

stringクラスにInメソッドを拡張メソッドとして定義します。

// StringExtension.cs

// stringクラスの拡張メソッドを定義するクラス
public static class StringExtension
{
    // 指定した文字列中に複数の酵素の中から1つでも一致するものが含まれているかどうかを確認する
    // パターン(1)
    public static bool In(this string str, bool ignoreCase, params string[] items)
    {
        return StringHelper.In(str, ignoreCase, items);
    }

    // 指定した文字列中に複数の酵素の中から1つでも一致するものが含まれているかどうかを確認する
    // パターン(2)
    public static bool In(this string str, bool ignoreCase, IEnumerable<string> items)
    {
        return StringHelper.In(str, ignoreCase, items);
    }
}

// stringを使った汎用操作を提供するクラス
public static class StringHelper
{
    public static bool In(string str, bool ignoreCase, params string[] items)
    {
        StringComparison c = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

        for (int i = 0; i < items.Length; i++)
        {
            if (In(str, c, items[i]))
            {
                return true;
            }
        }

        return false;
    }

    public static bool In(string str, bool ignoreCase, IEnumerable<string> items)
    {
        StringComparison c = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
        foreach (string item in items)
        {
            if (In(str, c, item))
            {
                return true;
            }
        }

        return false;
    }

    public static bool In(string str, StringComparison c, string item)
    {
        return str.IndexOf(item, c) != -1;
    }
}

使い方

上記クラスの使い方は以下の通りです。

リストと配列、IEnumerableが全て指定できます。Spanでも実装できますが…

大文字と小文字を区別しない場合、第1引数はtrueにします。

static void Main(string[] args)
{
    string str = "ABC123";

    // パターン(1)でチェック その1
    bool contains = str.In(false, "XX", "99", "AB", "12");
    if (contains)
    {
        // 見つかった
    }
    else
    {
        // 見つからない
    }

    // パターン(1)でチェック その2
    string[] items = new string[] { "XX", "99", "AB", "12" };
    contains = str.In(false, items);
    if (contains)
    {
        // 見つかった
    }
    else
    {
        // 見つからない
    }


    // パターン(2)でチェック
    IList<string> list = new List<string>() { "XX", "99", "AB", "12" };
    contains = str.In(false, list);
    if (contains)
    {
        // 見つかった
    }
    else
    {
        // 見つからない
    }

    // パター(2)でチェック
    IEnumerable<string> f()
    {
        yield return "XX";
        yield return "99";
        yield return "AB";
        yield return "12";
    }

    contains = str.In(false, f());
    if (contains)
    {
        // 見つかった
    }
    else
    {
        // 見つからない
    }
}

これで複数の候補の中から一致するものがあるかどうかをstringクラスで判定できます。