2008年06月05日

ジェネリックで加算は無理?

  
T Hoge<T>(T obj) where T : struct {
return obj + 1; // + 演算子は使えない
}

のようにC#で書きたいんだけど... できません。

それで、いろいろ試してみた。
IConvertibleインターフェースには、GetTypeCode() というメソッドがあって、これは、TypeCode列挙型を返してくれる。
これを利用すれば、できるかなって思って、

T Hoge<T>(T obj) where T : struct, IConvertible {
switch (obj.GetTypeCode()) {
case TypeCode.Int32:
Int32 n = obj.ToInt32(null);
return n;
case TypeCode.Int16:
Int16 n = obj.ToInt16(null);
return n;
case TypeCode.Int64:
Int64 n = obj.ToInt16(null);
return n;
}
}

なんてコードを書いてみた。
でも、悲しいことに(というかあたり前なんだけど)、求めた n を T型にキャストすることはできないから、コンパイルエラーになる。。

やはり、無理なのかな?

素直に、
int Hoge(int obj) {
return obj + 1;
}

long Hoge(long obj) {
return obj + 1;
}


って書けばいいんじゃないの?
はい、おっしゃる通りです。

なんで、こんなことをやろうとしたかと言えば、RangeValue<T> という範囲を扱うジェネリッククラスがあって、これに IEnumerable<T> インターフェースを付加したかったから。
その際、整数の場合はデフォルトで 1 ずつ加算した値を順に取り出せるような実装を考えていんだけど、無理みたいです。

結局、

public IEnumerable<T> ToEnumerable(Func<T, T> addFunction) {
...
}

というメソッドを作り、加算部分は、ラムダ式で指定してもらうことにした。


この記事へのコメント
はじめまして、よこけんと申します。

> 求めた n を T型にキャストすることはできないから、コンパイルエラーになる。。
ダウンキャストならばコンパイルエラーが発生しませんので、一度 IConvertible にキャストしてから T にキャストすれば行けますよ。

switch (obj.GetTypeCode())
{
case TypeCode.Int32:
return (T)(IConvertible)obj.ToInt32(null);
case TypeCode.Int16:
return (T)(IConvertible)obj.ToInt16(null);
case TypeCode.Int64:
return (T)(IConvertible)obj.ToInt16(null);
default:
throw new NotSupportedException();
}
Posted by よこけん at 2008年06月06日 20:50
よこけんさん、はじめまして。
なるほど、
where T : struct, IConvertible
て書いてあるので、IConvertibleから T にはキャストが
できるってわけですね。
勉強になりました。
Posted by Gushwell at 2008年06月07日 10:07
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51533037