次のようなものをコンパイルするのに失敗した後:
public class Gen<T> where T : System.Array
{
}
エラーあり
制約を特別なクラス「System.Array」にすることはできません
私は疑問に思い始めました、正確には何ですかis「特別クラス」ですか?
一般的な制約でSystem.Enum
を指定すると、多くの場合、同じ種類のエラーが発生するようです。 System.Object
、System.Delegate
、System.MulticastDelegate
、およびSystem.ValueType
でも同じ結果が得られました。
それらはもっとありますか? C#の「特別なクラス」に関する情報が見つかりません。
また、isがこれらのクラスについて特別なものであり、ジェネリック型制約として使用できないのは何ですか?
Roslynソースコードからは、ハードコードされた型のリストのように見えます。
switch (type.SpecialType)
{
case SpecialType.System_Object:
case SpecialType.System_ValueType:
case SpecialType.System_Enum:
case SpecialType.System_Delegate:
case SpecialType.System_MulticastDelegate:
case SpecialType.System_Array:
// "Constraint cannot be special class '{0}'"
Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
return false;
}
ソース: Binder_Constraints.cs IsValidConstraintType
GitHub検索を使用して見つけました: "制約は特別なクラスにできません"
同様の質問について、2008年のJon Skeetのコメントを見つけました。なぜSystem.Enum
制約notサポート。
私はこれが少し外れたトピックであることを知っていますが、彼はそれについてエリック・リッパート(C#チーム)に尋ね、彼らはこの答えを提供しました:
まず、あなたの推測は正しいです。制約の制限は、言語の大部分の成果物であり、CLRではありません。 (これらの機能を実行する場合、列挙可能な型がどのように指定されるかに関して、CLRで変更したいいくつかの小さな事柄がありますが、ほとんどこれは言語の仕事です。)
第二に、私は個人的に、デリゲート制約、列挙型制約、およびコンパイラがあなたからあなたを救おうとしているので、今日は違法な制約を指定する機能を持っていると思います。 (つまり、封印された型を制約として有効にするなど)。
ただし、スケジュールの制限により、これらの機能を次のバージョンの言語に組み込むことはできません。
[〜#〜] msdn [〜#〜] によると、クラスの静的リストです。
コンパイラエラーCS0702
制約を特別なクラス「識別子」にすることはできません次のタイプは制約として使用できません。
C#4.0言語仕様(コード化:[10.1.5]型パラメーターの制約)に従って、次の2つのことがわかります。
1]型はオブジェクトであってはなりません。すべてのタイプはオブジェクトから派生するため、許可されている場合、このような制約は効果がありません。
2] Tに1次制約または型パラメーター制約がない場合、その有効な基本クラスはオブジェクトです。
ジェネリッククラスを定義すると、クラスをインスタンス化するときにクライアントコードが型引数に使用できる型の種類に制限を適用できます。クライアントコードが制約で許可されていない型を使用してクラスをインスタンス化しようとすると、結果はコンパイルエラーになります。これらの制限は制約と呼ばれます。制約は、where contextualキーワードを使用して指定されます。 ジェネリック型を参照型に制限する場合は、classを使用します。
public class Gen<T> where T : class
{
}
これにより、ジェネリック型がintやstructなどの値型になることが禁止されます。
また、Constraintを特別なクラス 'identifier'にすることはできません。次のタイプは制約として使用できません。
フレームワークには、それらから派生したすべてのタイプに特別な特性を効果的に渡す特定のクラスがありますただし、それらの特性自体は所有していません。 CLR自体は、これらのクラスを制約として使用することを禁止していませんが、それらに制約されているジェネリック型は、具象型のように継承されない特性を取得しません。 C#の作成者は、このような動作が一部の人々を混乱させる可能性があり、その有用性を確認できなかったため、CLRでの動作を許可するのではなく、そのような制約を禁止する必要があると判断しました。
たとえば、書き込みが許可された場合:void CopyArray<T>(T dest, T source, int start, int count)
;タイプ_System.Array
_の引数を予期するメソッドにdest
およびsource
を渡すことができます。さらに、dest
とsource
が互換性のある配列型であるというコンパイル時の検証が行われますが、_[]
_演算子を使用して配列の要素にアクセスすることはできません。
void CopyArray<T>(T[] dest, T[] source, int start, int count)
は前者の方法が機能するほとんどすべての状況で機能するため、Array
を制約として使用できないことはほとんど回避するのが非常に簡単です。ただし、この方法には弱点があります。前者の方法は、引数の一方または両方が_System.Array
_型であるシナリオでは機能しますが、引数が互換性のない配列型である場合は拒否します。両方の引数の型が_System.Array
_であるオーバーロードを追加すると、コードは受け入れるべき追加のケースを受け入れますが、受け入れてはならないケースを誤って受け入れます。
特別な制約のほとんどを違法にする決定は厄介だと思います。意味的な意味がゼロになる唯一のものは、_System.Object
_ [それが制約として合法である場合、何でも満たすからです]。 _System.ValueType
_は、おそらくValueType
型の参照は値型とあまり共通していないため、あまり有用ではありませんが、Reflectionを含む場合にはおそらく何らかの値を持っている可能性があります。 _System.Enum
_と_System.Delegate
_の両方に実際の用途がありますが、C#の作成者はそれらを考えていなかったため、正当な理由で違法にされました。
以下は、C#4th Editionを介してCLRにあります。
型パラメーターには、ゼロの1次制約または1つの1次制約を指定できます。プライマリ制約は、シールされていないクラスを識別する参照タイプにすることができます。次の特別な参照タイプのいずれかを指定することはできません:System.Object、System.Array、System.Delegate、System。 MulticastDelegate、System.ValueType、System.Enum、またはSystem.Void。参照型制約を指定する場合、指定された型引数は同じ型または制約型から派生した型のいずれかになることをコンパイラに約束します。
「特別なクラス」/「特別なタイプ」の公式の定義は存在しないと思います。
あなたはそれらを「通常の」型のセマンティックで使用できない型と考えるかもしれません:
追伸リストにSystem.Void
を追加します。