PG日誌

受託系 PG が C# の事を書いています

任意の値型をジェネリック(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);
    }
    else if(_t == typeof(bool))
    {
        return (T)bool.Parse(value);
    }
    
    throw new NotSupportedException(_t + " is not suported.");
}

コンパイル前の入力している最中に以下のエラーが発生します。

エラー CS0030 型 'bool''T' に暗黙的に変換できません
エラー CS0030 型 'int''T' に暗黙的に変換できません

解決策

(T)にキャストする前にobject型に変換します。

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

おまけ

本当は正体不明の文字列を、チェックしないでParseすると以下の例外が発生します。

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

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

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

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

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