任意の値型をジェネリック(T)型にキャストする

ジェネリックの型の変数を int や bool などの値型にキャストして返却する方法の紹介です。

変換できないエラーが出る

以下の例では、型チェック後には型が判明しているのですが、コンパイルできずエラーになります。

public T Convert<T>(string key)
{
    string value = Config.GetValue(key);
    
    Type _t = typeof(T);
    if(_t == typeof(int))
    {
        return (T)int.Parse(value); // エラー CS0030 型 'bool' を 'T' に暗黙的に変換できません
    }
    else if(_t == typeof(bool))
    {
        return (T)bool.Parse(value); // エラー CS0030 型 'int' を 'T' に暗黙的に変換できません
    }
    throw new NotSupportedException(_t + " is not suported.");
}

解決方法

解決方法は、<T> にキャストする前に object にキャストします。

public T Convert<T>(string key)
{
    string value = Config.GetValue(key);
    
    Type _t = typeof(T);
    
    if(_t == typeof(int))
    {
        return (T)(object)int.Parse(value); // 一度object型にキャストする
    }
    else if(_t == typeof(bool))
    {
        return (T)(object)bool.Parse(value); // 一度object型にキャストする
    }
    throw new NotSupportedException(_t + " is not suported.");
}

int.Parseはエラーが出ることを考慮する

本来 int に変換できない文字列を int.Parse してしまうと以下の例外が発生します。

System.FormatException: 入力文字列の形式が正しくありません。

変換の失敗程度で例外を使用した場合"正常系では例外を使用しない"のイデオムに違反する可能性があるので、そういった場合はTryParseメソッドを使って成功したか失敗しながら処理を記述します。

if (int.TryParse(str, out int result))
{
    // 変換に成功した時の処理を書く
}
else
{
    // 変換に失敗居た時の処理を書く
    // この時、resultの中身は初期値が設定されている
}

やや乱暴ですが、変換に失敗した時は初期値を返す仕様の場合は以下のように書くこともできます。

int.TryParse(str, out int result);
return result;