C#2.0 仕様 (ジェネリック 1)

黄舟
黄舟オリジナル
2017-01-03 10:22:211381ブラウズ

この章は非常に長いため、いくつかの部分に分ける必要があるかもしれません:)

20.ジェネリック

20.1 ジェネリック クラス宣言

ジェネリック クラス宣言は、実際の型を形成するために型パラメーターを指定する必要があるクラスの宣言です。



クラス宣言では、オプションで型パラメータを定義できます。

class-declaration: (クラス宣言)
attributesopt class-modifiersopt class identifieropt type-parameter-listopt class –baseopt type-parameter-constraints-clauseopt class-body;opt (属性 オプションのクラス修飾子 オプションのクラス識別子 can オプションの型パラメーター リストオプションの基本クラス オプションの型パラメーター制約ステートメント オプションのクラス本体; オプション)
型パラメーターのリストが提供されない限り、クラス宣言で型パラメーター化された制約ステートメントを提供する必要はありません。

型パラメーターのリストを提供するクラス宣言は、ジェネリック クラス宣言です。さらに、ジェネリック クラス宣言またはジェネリック構造体宣言に埋め込まれたクラスは、それ自体がジェネリック クラス宣言です。構築型を作成するには、包含型の型パラメータが提供される必要があるためです。

ジェネリック クラスは構築型 (§20.5) を使用して渡されます。 )。ジェネリック クラス宣言

class List8742468051c85b06f0a0af9e3e506b5c{}
ここでは、構築された型 List8742468051c85b06f0a0af9e3e506b5c、Listbd43222e33876353aff11e13a7dc75f6、List74c6f25e79e205a53afa93c32870c098> の例をいくつか示します。構築型は 1 つ以上のパラメータを取ることができます。たとえば、List はオープン構築型と呼ばれます。 Listbd43222e33876353aff11e13a7dc75f6 など、型パラメーターを使用しない構築型は、閉じた構築型と呼ばれます。

ジェネリック型は「オーバーロード」できません。つまり、通常の型と同様に、ジェネリック型はスコープ内で一意の名前を付ける必要があります。


class C{}
class Cd94943c0b4933ad8cac500132f64757f{}//エラー、C が 2 回定義されています
class Cf3887e50b478d7d3734323cd28ecc8ff{}//エラー、C が 2 回定義されています
ただし、修飾されていない型名ではルックアップ (§20.9.3) およびメンバー アクセス (§20.9.4) で使用される型ルックアップ ルールでは、型パラメーターの数が考慮されます。

20.1.1 型パラメータ

型パラメータはクラス宣言で指定できます。各型パラメーターは、構築型の作成に使用される型パラメーターのプレースホルダーを示す単純な識別子です。型パラメーターは、後で提供される型の正式なプレースホルダーです。対照的に、型パラメータ §20.5.1) は、構築された型が参照されるときの実際の型の単なるプロキシです。

type-parameter-list: (型パラメータリスト:)
parameters type-parameter (型パラメータ、型パラメータ)
type-parameter: (型パラメータ:)
attributesopt identifier (属性のオプションの識別子)

クラス宣言内の各型パラメータは、クラスの宣言空間 (§3.3 ) にあり、名前を定義します。したがって、クラスで宣言された別の型パラメーターまたはメンバーと同じ名前を持つことはできません。型パラメータに型自体と同じ名前を付けることはできません。

クラス内の型パラメーターのスコープ (§3.7)。基底クラス、型パラメーター制約ステートメント、クラス本体が含まれます。クラスのメンバーとは異なり、派生クラスには拡張されません。そのスコープ内では、型パラメーターを型として使用できます。

type (型):

value-type (値型)
reference-type (参照型)
type-parameter (型パラメータ)
型パラメータはさまざまな実際の型引数によってインスタンス化できるため、型パラメータには他のタイプとは操作や制限が若干異なります。以下のものが含まれます。

型パラメーターを使用して、基本型またはインターフェイスを直接宣言することはできません。
型パラメーターのメンバー検索ルールについては、制約が存在する場合、型パラメーターに適用される制約に依存します。詳細については、§20.7.4 を参照してください。



型パラメーターに可能な変換は、型パラメーターに適用される制約 (存在する場合) によって異なります。詳細については、§20.7.4 を参照してください。
型パラメータがクラス制約 (§20.7.4) によって制約されていない限り、リテラル null は型パラメータで指定された型に変換できません。ただし、代わりにデフォルト値式 (§20.8.1) を使用することもできます。さらに、型パラメータで指定された型の値は、「==」および「!=」を使用して null と比較される場合があります (§20.8.4)。
型パラメーターがコンストラクター制約 (§20.7) によって制約されている場合、新しい式は 1 つの型パラメーターでのみ使用できます。
型パラメータは属性内のどこでも使用できません。
型パラメータはメンバー アクセスに使用したり、静的メンバーや入れ子になった型の型名を表すことはできません (§20.9.1、§20.9.4)。
安全でないコードでは、型パラメータをマネージド型として使用することはできません (§18.2)。

型として、型パラメーターは純粋にコンパイル時の構造です。実行時、各型パラメーターは、ジェネリック型宣言で提供される型引数によって指定される実行時型にバインドされます。このため、実行時には、型パラメータで宣言された変数の型は閉じた型になります (§20.5.2)。実行時に実行されるすべてのステートメントと式は、そのパラメーターによって型引数として提供される実際の型の型パラメーターを使用します。



20.1.2 インスタンス型

すべてのクラス宣言には、それに関連付けられた構築型、つまりインスタンス型があります。ジェネリック クラス宣言の場合、インスタンス型は型宣言から構築型 (§20.4) を作成することによって形成され、型パラメーターに対応する各型引数が使用されます。インスタンス化された型は型パラメーターを使用するため、型パラメーターのスコープ内 (クラス宣言内) でのみ有効です。インスタンスの型は、クラス宣言内の this の型です。非ジェネリック クラスの場合、インスタンス型は単なる宣言された型です。以下に、宣言されたいくつかのクラスとそのインスタンス タイプを示します。

class A<T> //实例类型:A<T>
{
class B{} //实例类型:A<T>.B
class C<U>{} //实例类型:A<T>.C<U>
}
class D{} //实例类型:D

20.1.3 基本クラスの仕様

クラス宣言で指定された基本クラスは構築型である可能性があります (§20.5)。基本クラス自体を型パラメーターにすることはできませんが、そのスコープ内に型パラメーターを含めることはできます。

class Extendd94943c0b4933ad8cac500132f64757f: V{}//エラー、型パラメータが基底クラスとして使用されています
ジェネリック クラス宣言では System.Attribute を直接または間接基底クラスとして使用できません。

クラス宣言で指定される基本インターフェースは、構築されたインターフェース型にすることができます (§20.5)。基本インターフェイス自体を型パラメーターにすることはできませんが、そのスコープ内に型パラメーターを含めることはできます。次のコードは、構築された型を実装および拡張する方法を示しています。


class C<U,V>{}
Interface I1<V>{}
class D:C<string , int>,I1<string>{}
class E<T>:C<int,T> ,I1<T>{}

ジェネリック型によって宣言された基本インターフェイスは、§20.3.1 で説明されている一意性の規則を満たさなければなりません。

基本クラスまたはインターフェースのメソッドをオーバーライドまたは実装するクラスのメソッドは、特定の型に適切なメソッドを提供する必要があります。以下のコードは、メソッドをオーバーライドして実装する方法を示しています。これについては、§20.1.10 で詳しく説明します。



class C<U,V>
{
public virtual void M1(U x , List<V> y){…}
}
interface I1<V>
{
V M2(V x);
}
class D:C<string , int>,I1<string>
{
public override void M1(string x , List<int> y){…}
public string M2(string x){…}
}

20.1.4 ジェネリッククラスのメンバー

泛型类的所有成员都可以直接地或者作为构造类型的一部分,从任何封闭类(enclosing class)中使用类型参数。当特定的封闭构造类型在运行时被使用时,类型参数的每次使用都由构造类型所提供的实际类型实参所代替。例如


class C<V>
{ 
public V f1; 
public C<V> f2=null;
public C(V x){
this.f1 = x;
this.f2 = this;
}
}
class Application
{
static void Main(){
C<int> x1= new C<int >(1);
Console.WriteLine(x1.f1); //打印1
C<double> x2 = new C<double>(3.1415);
Console.WriteLine(x2.f1); //打印 3.1415
}
}

在实例函数成员之内,this的类型就是声明的实例类型(§20.1.2)。

除了使用类型参数作为类型和成员,在泛型类声明中也遵循和非泛型类成员相同的规则。适用于特定种类成员的附加规则将在后面几节进行讨论。

20.1.5泛型类中的静态字段

在一个泛型类声明中的静态变量,在相同封闭构造类型(§20.5.2)所有实例中被共享,但在不同封闭构造类型的实例中[1],是不被共享的。这些规则不管静态变量的类型包含那种类型参数都适用。

例如

class C<V>
{
static int count = 0;
public C()
{
count++;
}
public static int Count{
get{return count;}
}
}
class Application
{
static void Main()
{
C<int> x1 = new C<int>();
Console.WriteLine(C<int>.Count);//打印 1
C<double> x2 = new C<double>();
Console.WriteLine(C<int>.Count);//打印 1
C<int> x3 = new C<int>();
Console.WriteLine(C<int>.Count);//打印 2
}
}

[1] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如Listbd43222e33876353aff11e13a7dc75f6 和List98c455a79ddfebb79781bff588e7b37e 这二者的实例是不能共享静态变量的。

以上就是C#2.0 Specification(泛型一)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:C# 2.0 仕様 (4)次の記事:C# 2.0 仕様 (4)