cannot be used as type parameter の原因と直し方
where T : IComparable<T>のような制約を満たさない型を、ジェネリックメソッドの型引数として渡そうとすると出るコンパイルエラーです。
エラーメッセージの読み方
Program.cs(7,34): error CS0311: The type 'Program.NotComparable' cannot be used as type parameter 'T' in the generic type or method 'Program.Max<T>(T, T)'. There is no implicit reference conversion from 'Program.NotComparable' to 'System.IComparable<Program.NotComparable>'.
Program.cs- ファイル名
7- 行番号
34- 列番号 — この位置でコンパイラが解析に失敗しました
CS0311- エラーコード — 検索するとMicrosoftの解説ページが見つかります
The type 'Program.NotComparable' cannot be used as type parameter 'T' in the generic type or method 'Program.Max<T>(T, T)'. There is no implicit reference conversion from 'Program.NotComparable' to 'System.IComparable<Program.NotComparable>'.- 内容 — 期待していたもの、または受け付けられなかったもの
このエラーが出る典型パターン
パターン1
1 class Program { 2 static T Max<T>(T a, T b) where T : System.IComparable<T> { 3 return a.CompareTo(b) > 0 ? a : b; 4 } 5 class NotComparable { } 6 static void Main(string[] args) { 7 System.Console.WriteLine(Max(new NotComparable(), new NotComparable())); ^ 8 } 9 }
Program.cs(7,34): error CS0311: The type 'Program.NotComparable' cannot be used as type parameter 'T' in the generic type or method 'Program.Max<T>(T, T)'. There is no implicit reference conversion from 'Program.NotComparable' to 'System.IComparable<Program.NotComparable>'.
MaxはIComparable<T>を実装した型しか受け取れません。独自クラスにその実装がなければ型引数として使えません。
直し方: new NotComparable(), new NotComparable() を 1, 2 にします。
広告
広告スロット(未設定)
パターン2
1 class Program { 2 static T Clamp<T>(T value, T min, T max) where T : System.IComparable<T> { 3 if (value.CompareTo(min) < 0) return min; 4 if (value.CompareTo(max) > 0) return max; 5 return value; 6 } 7 class Tag { } 8 static void Main(string[] args) { 9 System.Console.WriteLine(Clamp(new Tag(), new Tag(), new Tag())); ^ 10 } 11 }
Program.cs(9,34): error CS0311: The type 'Program.Tag' cannot be used as type parameter 'T' in the generic type or method 'Program.Clamp<T>(T, T, T)'. There is no implicit reference conversion from 'Program.Tag' to 'System.IComparable<Program.Tag>'.
ClampもIComparable<T>制約を課しています。比較できない型は制約違反としてコンパイル時に弾かれます。
直し方: new Tag(), new Tag(), new Tag() を 5, 1, 10 にします。
パターン3
1 class Program { 2 static bool IsGreater<T>(T a, T b) where T : System.IComparable<T> { 3 return a.CompareTo(b) > 0; 4 } 5 class Blob { } 6 static void Main(string[] args) { 7 System.Console.WriteLine(IsGreater(new Blob(), new Blob())); ^ 8 } 9 }
Program.cs(7,34): error CS0311: The type 'Program.Blob' cannot be used as type parameter 'T' in the generic type or method 'Program.IsGreater<T>(T, T)'. There is no implicit reference conversion from 'Program.Blob' to 'System.IComparable<Program.Blob>'.
IsGreaterも比較可能な型しか受け付けません。制約は実行前、コンパイル時にチェックされます。
直し方: new Blob(), new Blob() を 3, 1 にします。
よくある誤解
ジェネリックの制約違反は実行時ではなくコンパイル時に検出されます。型引数を明示していなくても、コンパイラは呼び出しから逆算して制約をチェックします。
まとめ
cannot be used as type parameterは中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。