#概要
ジェネリック制約について使う機会が多くなったのでこの機会に調べたことを自分なりにまとめようと思います。
#ジェネリック制約とは
ジェネリックを使う際に宣言の後ろに
[where ジェネリックで使う型 : 制限したい型]
をつけることで使える型を制限出来ることです。こうすることによってこのクラスでしか使えないようにしたいとか、このクラスでは使ってほしくないなどの使い方が出来るようになります。
・例 ジェネリックの対象をクラスのみにしたい場合
public class MyClass<T> where T : class
{
}
#一覧
簡単にどんなのがあるのかまとめました。
詳しい説明は公式ドキュメントに載ってます。
ジェネリック制約 | 説明 |
---|---|
where T : class | class(参照型)のみ制約 |
where T : struct | Nullableを除く全ての値型のみ制約 |
where T : <クラス名> | 指定したクラスのみで制約 |
where T : <インターフェース名> | 指定したインターフェースのみで制約 |
where T : new() | 引数なしのパブリックコンストラクタがある型のみで制約 |
where T : U | Uに基づいた型で制約される |
#ルール
ジェネリック制約にはいくつかルールがあります
・ジェネリックの制限
・アクセスレベルの統一
#ジェネリックの制限
全ての型でジェネリック制約が使えるわけではなく、
一定の型はジェネリック制約で指定できません。
C#のバージョンによっては使えたり使えなかったりするので注意です。
公式ドキュメントからの引用
where (ジェネリック型制約) (C# リファレンス)
一部の型は、基底クラスの制約として許可されません (Object、Array、ValueType)。 C# 7.3 より前は、Enum、Delegate、MulticastDelegate も基底クラスの制約として許可されていません。 次の例では、この型は基底クラスとして指定できるようになったことを示しています。
参考
ジェネリックの利点と制限事項
https://msdn.microsoft.com/ja-jp/library/ms172194(v=vs.110).aspx
コンパイラ エラー CS0702
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-messages/cs0702
#アクセスレベルの統一
ジェネリック制約を使おうとしてるクラスとジェネリック制約の対象のクラスのアクセスレベルを統一する必要があります。
例えば、ジェネリック制約を利用しようとしてるクラスのアクセスレベルがpublicで、ジェネリック制約の対象のクラスのアクセスレベルがprivateだったらコンパイルエラーを起こします。
private class MyPrivateClass
{
}
public class MyClass<T> where T : MyPrivateClass
{
}
アクセシビリティに一貫性がありません。制約型'MyPrivateClass'のアクセシビリティは'MyClass<T>'よりも低く設定されています。
コンパイラ エラー CS0703
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-messages/cs0703
#最後に
全ての型で使えるわけではない点など、細かい点を押さえれば結構便利な機能だと思いました。
このクラスのみで使用したい、このインターフェースを実装してるクラスのみに使用したいなど
利用するケースは結構あると思っていますので、積極的に使っていきたいですね。