「特別クラス」とは正確には何ですか?


114

コンパイルするために次のようなものを得ることに失敗した後:

public class Gen<T> where T : System.Array
{
}

エラーあり

制約を特別なクラス `System.Array 'にすることはできません

「特別クラス」とは一体何なのでしょうか?

System.Enum一般的な制約で指定すると、多くの場合、同じ種類のエラーが発生します。私は同じ結果を得たSystem.ObjectSystem.DelegateSystem.MulticastDelegateSystem.ValueTypeあまりにも。

それらはもっとありますか?C#で「特殊クラス」に関する情報が見つかりません。

また、ジェネリック型の制約として使用できないほど特別なもの何ですか?


14
これは直接の複製ではないと思います。問題は、「なぜこれを制約として使用できないのか」ではなく、「これらの特別なクラスとは何か」です。私はそれらの質問を見てきましたが、制約として使用することが役に立たない理由を述べているだけで、「特別なクラス」が実際に何であるか、なぜそれが特別であると考えられているのかを説明していません。
Adam Houldsworth、2015

2
私の経験では、使用されているクラスを直接使用することはできず、他の構文を介して暗黙的にのみ使用できるクラスは、特別なクラスです。Enumは同じカテゴリに分類されます。何が彼らを特別なものにしているのか、私にはわかりません。
Lasse V. Karlsen、2015

@AndyKorneyev:その質問はちょっと違う。「特別クラス」の定義および/またはこれらの包括的なリストを求めています。その質問は、単にSystem.Arrayがジェネリック型制約になり得ない理由を尋ねるだけです。
Mints97 2015

ドキュメントからは、「[...]システムとコンパイラのみがArrayクラスから明示的に派生できる」と述べています。これがおそらくそれを特別なクラスにする理由です-それはコンパイラによって特別に扱われます。
RB。

1
@RB .:間違っています。これは有効なので、このロジックは「特別なクラス」でSystem.Objectないことを意味しますがpublic class X : System.Object { }System.Objectそれでも「特別なクラス」です。
Mints97

回答:


106

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検索を使用して見つけた:「制約は特別なクラスにすることはできません」


1
@kobi 702は、コンパイラーの出力(この質問では引用されなかった)やその他の回答に見られるように、コンパイラーエラーCS0702になります。
AakashM 2015

1
@AakashM-ありがとう!コンパイルしようとしたのですが、なんらかの理由でエラー番号が表示されませんでした。それからそれを見つけるのに 5分かかり、コメントを編集するのに十分な時間がありませんでした。悲しい話。
Kobi 2015

1
@Kobi:出力ウィンドウを確認する必要があります。そこで、正確なコンパイラエラーコード番号を見つけますCS0702
Tim Schmelter、2015

9
では、本当の問題は、なぜこれらの特別なクラスなのかということです。
デビッドは、モニカを

@DavidGrinberg多分理由は、これらの型から直接継承できない(を除くobject)か、少なくともそれと何らかの関係があるためです。またwhere T : Array、AssayをTとして渡すこともできますが、これはおそらくほとんどの人が望んでいることではありません。
IllidanS4はモニカに2016

42

私は同様の質問について2008年のジョンスキートのコメントを見つけました:なぜSystem.Enum制約はないのですか?サポートされています。

私はこれが少し外れたトピックあることを知っていますが、彼はEric Lippert(C#チーム)にそれについて尋ね、彼らはこの答えを提供しました:

まず、あなたの予想は正しいです。制約の制限は、言語の大きなアーティファクトによるものであり、CLRではありません。(これらの機能を実行する場合、列挙可能な型の指定方法に関してCLRで変更したいいくつかのマイナーな事項がありますが、これは主に言語処理です。)

第二に、私は個人的に、デリゲート制約、列挙型制約、およびコンパイラーがあなたからあなたを救おうとしているので今日では違法である制約を指定する機能が欲しいです。(つまり、シールされた型を制約として合法にするなど)。

ただし、スケジュールの制限により、これらの機能を次のバージョンの言語に組み込むことはできません。


10
@YuvalItzchakov-Github \ MSDNの方が優れていますか?C#チームは問題または同様の問題に関して具体的な回答を出しました。それは実際には誰にも害を及ぼすことはありません。ジョンスキートはちょうどそれらを引用し、それがC#..になったときに、かなり信頼性がある
アミールポポビッチ

5
動揺する必要はありません。私はこれが有効な答えではないという意味ではありませんでした:)ジョンスキートである財団に関する私の考えを共有していただけです; p
Yuval Itzchakov

40
ちなみに私はあなたがそこに引用している私だと思います。:-)
Eric Lippert、2015

2
@EricLippert-これにより、見積もりの​​信頼性がさらに高まります。
Amir Popovich

回答のリンクのドメインは死んでいます。
2017

25

MSDNによると、これはクラスの静的リストです。

コンパイラエラーCS0702

制約を特別なクラス 'identifier'にすることはできません。次のタイプは制約として使用できません。

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType。

4
かっこいい、正解のようです、良い発見!しかしSystem.MulticastDelegate、リストのどこにありますか?
Mints97 2015

8
@ Mints97:わからない、おそらくドキュメントの欠如?
Tim Schmelter、2015

これらのクラスからも継承できないようです。
David Klempfner、

14

C#4.0言語仕様(コード化:[10.1.5]型パラメーターの制約)のとおり、次の2つのことがわかります。

1]タイプはオブジェクトであってはなりません。すべてのタイプはオブジェクトから派生するため、そのような制約は許可されていても効果がありません。

2] Tに1次制約または型パラメーター制約がない場合、その有効な基本クラスはオブジェクトです。

ジェネリッククラスを定義する場合、クラスをインスタンス化するときにクライアントコードが型引数に使用できる型の種類に制限を適用できます。クライアントコードが、制約で許可されていない型を使用してクラスをインスタンス化しようとすると、コンパイル時エラーが発生します。これらの制限は制約と呼ばれます。制約は、whereコンテキストキーワードを使用して指定されます。 ジェネリック型を参照型に制限する場合は、:クラスを使用します。

public class Gen<T> where T : class
{
}

これにより、intやstructなどのジェネリック型が値型になることが禁止されます。

また、制約を特別なクラス '識別子'にすることはできません。次のタイプは制約として使用できません。

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType。

12

フレームワークには、特殊な特性をそれらから派生したすべての型に効果的に渡す、それら自体の特性を持たない特定のクラスがあります。CLR自体は、これらのクラスを制約として使用することを禁止していませんが、それらに制約されているジェネリック型は、具象型のように非継承特性を取得しません。C#の作成者は、そのような動作は一部の人々を混乱させる可能性があり、有用性を確認できなかったため、CLRでのように動作させるのではなく、そのような制約を禁止する必要があると判断しました。

場合は、例えば、1を書き込むことが許されました:void CopyArray<T>(T dest, T source, int start, int count); 型の引数を期待するメソッドに渡しdestたりsource、メソッドに渡すことができSystem.Arrayます。さらに、一つはコンパイル時の検証ことになるだろうdestし、source互換性のある配列型だったが、一つは使用して、配列のアクセス要素にできないだろう[]演算子。

前者の方法が機能するほとんどすべての状況で機能するArrayため、制約として使用できないことは、ほとんどの場合回避するのが非常に簡単void CopyArray<T>(T[] dest, T[] source, int start, int count)です。ただし、弱点があります。前者の方法は、引数の一方または両方が型であるというシナリオSystem.Arrayで機能し、引数が互換性のない配列型である場合を拒否します。両方の引数が型であるオーバーロードを追加するSystem.Arrayすると、コードは受け入れるべき追加のケースを受け入れますが、受け入れられないケースを誤って受け入れます。

特別な制約のほとんどを非合法化する決定は厄介だと私は思います。意味論的な意味を持たない唯一のものは、System.Object[それが制約として合法であるならば、何でもそれを満足するであろうから]であろう。 System.ValueType型の参照はValueType値の型とあまり共通点がないため、おそらくあまり役​​に立ちませんが、Reflectionが関係する場合には、おそらく何らかの値を持つ可能性があります。両方System.EnumSystem.Delegateいくつかの実際の用途がありますが、C#のクリエイターは、それらが正当な理由なく非合法化している彼らは考えていなかったからです。


10

以下は、C#4th Editionを介してCLRにあります。

主な制約

タイプパラメータは、ゼロの主制約または1つの主制約を指定できます。主制約は、シールされていないクラスを識別する参照タイプにすることができます。System.ObjectSystem.ArraySystem.DelegateSystem.MulticastDelegateSystem.ValueTypeSystem.Enum、またはSystem.Voidのいずれかの特別な参照タイプを指定することはできません。参照型制約を指定する場合、指定した型の引数が同じ型か、制約型から派生した型のいずれかになることをコンパイラに約束します。


C#LSセクション10.1.4.1::も参照してください:クラス型の直接の基底クラスは、以下のタイプのいずれであってはなりませんがSystem.ArraySystem.DelegateSystem.MulticastDelegateSystem.Enum、またはSystem.ValueType。さらに、ジェネリッククラス宣言はSystem.Attribute、直接または間接の基本クラスとして使用できません。
Jeroen Vannevel

5

「特別なクラス」/「特別なタイプ」の公式の定義は存在しないと思います。

「通常の」タイプのセマンティクスでは使用できないタイプaaについて考えることができます。

  • それらを直接インスタンス化することはできません。
  • それらからカスタムタイプを直接継承することはできません。
  • それらを操作するためのコンパイラーの魔法があります(オプション)。
  • それらのインスタンスの直接的な使用は、少なくとも役に立たない(オプションで、上でジェネリックを作成したとしたら、どのジェネリックコードを作成するのか?)

PS私System.Voidはリストに追加します。


2
System.Void一般的な制約として使用すると、まったく異なるエラーが発生します=)
Mints97

@ Mints97:true。しかし、質問が「特別」についてである場合、はい、void非常に特別です。:)
デニス

@Dennis:制約された型のパラメーターがいくつかあるコードでは、データを一方から他方に移動System.Arrayするなどのメソッドを使用できますArray.Copy。制約されたタイプのパラメータを持つコードはそれらSystem.Delegate使用でき、結果を適切なタイプにキャストできます。ジェネリックな既知のタイプを効果的に使用するには、そのようなタイプごとに1回Reflectionを使用しますが、ジェネリックメソッドは、非ジェネリックメソッドよりも10倍高速です。Delegate.CombineEnumHasAnyFlag
スーパーキャット2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.