ホームページ  >  記事  >  バックエンド開発  >  C# 2.0 仕様 (ジェネリック 6)

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

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

ジェネリック 5 への接続

20.8 式とステートメント

一部の式とステートメントの演算がジェネリック用に変更されました。このセクションでは、これらの変更について説明します。

20.8.1 デフォルト値式

デフォルト値式は、型のデフォルト値を取得するために使用されます (§5.2)。通常、型パラメーターにはデフォルト値式が使用されます。これは、型パラメーターが値型または参照型の場合、それがまだ存在していない可能性があるためです。 (null型から型パラメータへの変換はありません。)

primary-no-array-creation-expression:(基本无数组创建表达式:)
…
default-value-expression(默认值表达式)
default-value-expression:(默认值表达式:) 
primary-expression . default (基本表达式 .default)
predefined-type . default(预定义类型. default)

デフォルト値式に基本式が使用されており、基本式を型に分割できない場合、コンパイル時にエラーが発生します。ただし、§7.5.4.1 で説明されている規則は、E.default を形成するコンポーネントにも適用されます。
デフォルト値式の左側が参照型に対して実行時に評価される場合、結果はその型に null 変換されます。デフォルト値式の左側が実行時に値型に対して評価される場合、結果は値型のデフォルト値になります (§4.1.2)。
型が参照型またはクラス制約のある型パラメータの場合、デフォルト値式は定数式 (§7.15) です。さらに、型が sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、10 進数、または bool のいずれかの場合、デフォルト値の式は定数式になります。

20.8.2 オブジェクト作成式

オブジェクトの共通式の型を型パラメータにすることができます。オブジェクト作成式の型として型パラメータを指定する場合、以下の2つの条件を満たさなければコンパイル時にエラーが発生します

実際のパラメータリストは削除する必要があります
new()形式のコンストラクタ型パラメーターに指定する必要があります 関数の制約

オブジェクト作成式は、型パラメーターがバインドされているランタイム型のインスタンスを作成し、その型の既定のコンストラクターを呼び出すことによって実行できます。ランタイム型は参照型または値型にすることができます。

20.8.3 演算子の種類

typeof 演算子は型パラメータに使用できます。結果は、type パラメーターにバインドされたランタイム型の System.Type オブジェクトです。 typeof 演算子を使用して型を構築することもできます。

class X <T>
{
public static void PrintTypes()
{
Console.WriteLine(typeof(T).FullName);
Console.WriteLine(typeof(X<X<T>>).FullName);
}
}
class M
{
static void Main()
{
X<int>.PrintTypes();
}
}

前の手順では次のように出力されます。

System.Int32
X<X<Sytem.Int32>>
Typeof运算符不能用于没有指定类型实参的泛型类型声明的名字。
class X<T>{…}
class M
{
static void Main()
{
Type t = typeof(X); //错误,X需要类型实参
}
}

20.8.4 参照型等価演算子

T がクラス制約によって制約されている場合、参照型等価演算子を使用して型パラメーター T の値を比較できます。
参照型等価演算子を使用すると、T にクラス制約がない場合でも、型パラメーター T の実パラメーターを null である他の実際のパラメーターと簡単に比較できます。実行時に、T が値型の場合、比較の結果は false になります。

次の例では、制約なしの型パラメーター型の実パラメーターが null かどうかを確認します。

class C<T>
{
void F(T x)
{
if(x==null) thow new ArgumentNullException();
…
}
}

T が値型を表すことができる場合でも、x==null 構造は許可され、T が値型の場合、その結果は単純に false として定義されます。

20.8.5 is运算符

在开放类型上的is运算符操作遵循通常的规则(§7.9.9)。如果e或T的编译时类型是一个开放类型,那么在运行时对于e和T将总是执行动态类型检查。

20.8.6as运算符

只要T有一个类约束,类型参数T可被用在as运算符的右边。这种限制是需要的,因为值null可能被作为运算符的结果返回。

class X
{
public T F<T>(object o) where T:Attribute
{
return o as T; //ok,T有一个类约束
}
public T G<T>(object o)
{
return o as T; //错误,T没有约束
}

}
在as运算符(§7.9.10)的当前规范中,对于表达式e as T最后一点表明,如果从e的编译时类型到T,不存在有效的显式引用转换,将会出现编译时错误。对于泛型,这条规则稍微作了修改。如果E的编译时类型或T是一个开放类型,在这种情况下将不会出现编译时错误;相反,运行时检查将会执行。

20.8.7异常语句

对于开放类型,throw(§8.9.5)和try(§8.10)的通常规则是适用的。

只要类型参数具有System.Exeption异常(或子类具有)作为类约束,那么throw语句可以被用作其类型有一个类型参数给定的表达式。 
只要类型参数System.Exception(或子类子类具有)作为类约束,那么在catch语句中的命名的类型可能是一个类型参数。

20.8.8 lock语句

lock语句可以被用作其类型由一个类型参数给定的表达式。如果表达式的运行时类型是一个值类型,lock将没有效果(因为对于装箱值不能有任何其他的引用)。

20.8.9 using 语句

using 语句(§8.13)遵循通常的规则:表达式必须被隐式的转换到System.IDisposable。如果类型参数通过System.IDisposable而约束,那么该类型的表达式可以使用using 语句。

20.8.10 foreach语句

给定如下形式的foreach语句
foreach(ElementType element in collection) statement
如果集合表达式是一个没有实现集合模式的类型,但为每个类型T实现了构造接口System.Collections.Generic.IEnumerable8742468051c85b06f0a0af9e3e506b5c,那么foreach语句的扩展是

IEnumerator<T> enumerator = ((IEnuemrable<T>)(collection).GetEnumerator();
try
{
where (enumerator.MoveNext()){
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally{
enumerator.Dispose();
}

20.9查找规则修订

泛型修改了用于查找和绑定名字的某些基本规则。下面几节在考虑泛型的情况下,重新叙述了所有的基本名字查找规则。

20.9.1命名空间和类型名字

次のコンテンツは §3.8 を置き換えることができます。
C# プログラムには、名前空間または型名の指定を必要とするコンテキストがいくつかあります。どの形式の名前も、「.」マークで区切られた 1 つ以上の識別子で構成されます。
namespace-name: (名前空間名:)
namespace-or-type-name (名前空間または型名)
type-name: (型名:)
namespace-or-type-name (名前空間または型名) )
namespace-or-type-name: (名前空間または型名:)
識別子 type-argument-list opt (識別子の型引数リストはオプション)
namespace-or-type-name 識別子 type-argument-list opt (名前空間または型名。識別子の型引数リストはオプション)
名前空間名は、名前空間を参照する名前空間名または型名 (namespace-or-type-name) です。以下で説明する決定を参照してください。名前空間または名前空間名の型名は名前空間を参照する必要があります。参照しないとコンパイル時エラーが発生します。名前空間名に型引数を含めることはできません (型引数を持つことができるのは型のみです)。
型名は、型を参照する名前空間または型名です。以下で説明する決定を参照してください。型名の名前空間または型名は型を参照する必要があります。そうでない場合は、コンパイル時エラーが発生します。
名前空間または型名の意味は次のように決まります。

名前空間または型名が I または I の形式である場合、I は単一の識別子、 は型引数のオプションのリストです。

- 名前空間または型名がジェネリック メソッド宣言内にあり、その宣言に、型引数リストを指定しない I で指定された名前の型パラメーターが含まれている場合、名前空間または型名は型パラメーターを参照します。
- それ以外の場合、名前空間または型名が型宣言内にある場合は、型 T (f53db7e3537772cbf9ba1634d2b17fe620.1.2) の各インスタンスについて、その型宣言のインスタンス型から開始し、それぞれを続行します。囲むクラスまたは構造体の型宣言 (存在する場合)
u I で指定された名前を含む型パラメーター T に宣言が指定されておらず、型引数リストがない場合、名前空間または型名はその型パラメーターを参照します。


u それ以外の場合、I が T のアクセス可能なメンバーの名前であり、そのメンバーが一致する数の型パラメーターを持つ型である場合、名前空間または型名は型 T.I または型 T.I- それ以外の場合、表示される名前空間または型名で始まり、それを囲む各名前空間 (存在する場合) に続き、グローバル名前空間で終わる各名前空間 N について、エンティティが見つかるまで次の手順が計算されます。
u I が N の名前空間内の名前で、型引数リストが指定されていない場合、名前空間または型名はその名前空間を参照します。
u それ以外の場合、I が一致する数の型引数を持つ N 内のアクセス可能な型の名前である場合、名前空間または型名は、指定された型引数で構築された型を参照します。
u それ以外の場合、名前空間または型名が N の名前空間宣言で囲まれた位置にある場合
- 名前空間宣言に I で指定された名前を持つ using エイリアス ディレクティブが含まれており、I がインポートされた名前空間または型を保持し、引数リストが指定されている場合、名前空間または型名はその名前空間または型を参照します
- それ以外の場合、名前空間宣言の using namespace ディレクティブによってインポートされた名前空間に、指定された名前、一致する型引数の型を持つ型が含まれている場合、この場合、名前空間または型名は、指定された型引数から構築された型を参照します。
- そうしないと、名前空間宣言の using namespace ディレクティブによってインポートされた名前空間に、型パラメーターの数と一致する指定された名前を持つ複数の型が含まれている場合、名前空間または型名があいまいになり、間違いが発生します。
- それ以外の場合、名前空間または型名が未定義となり、コンパイル時エラーが発生します。


l それ以外の場合、名前空間または型名は N.I または N.I の形式になります。ここで、N は名前空間または型名、I は識別子、 です。 ; はオプションの型引数のリストです。 N は、名前空間または型名として最初に決定されます。 N の決定が失敗すると、コンパイル時エラーが発生します。それ以外の場合、N.I または N.I は次のように決定されます。
- N が名前空間を参照し、I が N に埋め込まれた名前空間名で、型引数リストが指定されていない場合、名前空間または型名は埋め込まれた名前空間を参照します。
- それ以外の場合、N が名前空間を参照し、I が一致する数の型引数を使用して N でアクセス可能な型の名前である場合、名前空間または型名は、指定された型引数から構築された型を参照します。
- それ以外の場合、N がクラスまたは構造体の型を指し、I が一致する型パラメーターを持つ N に埋め込まれたアクセス可能な型の名前である場合、名前空間または型名は、指定された引数で構築された型を指します。
- それ以外の場合、N.I は無効な名前空間名であり、コンパイル時エラーが発生します。

20.9.2 メンバー検索

以下の内容は置き換え可能です§7.3

メンバー検索はコンテキストでの意味に基づいて型を決定するプロセスです。式内では、メンバーの検索は、単純な名前評価として、またはメンバー アクセスとして実行できます (§20.9.4)。
タイプ T の名前 N のメンバー検索は、次の規則に従って決定されます。

まず、N という名前のアクセス可能なメンバーのセットが決定されます。

- T が型パラメーターの場合、 T のクラス制約またはインターフェイス制約として指定された各型で、 object 内の N の名前付きメンバーのセットとともに、このセットは名前付きのアクセス可能なメンバーの和集合になります。
- それ以外の場合、このセットは、オブジェクトの N の継承されたメンバーと名前付きのアクセス可能なメンバーを含む、T の N のすべての名前付きアクセス可能なメンバーで構成されます。 T が構築型の場合、§20.5.4 で説明されているように型引数を置換することによってメンバーのセットが取得されます。 override 修飾子を含むメンバーはコレクションから除外されます。




その後、他のメンバーを通して隠されているメンバーはこのセットから削除されます。セット内の各メンバー S.M について、S は M が宣言されている型であり、次のルールが適用されます

- M が定数、フィールド、プロパティ、イベント、または列挙メンバーの場合、S のすべての基底で宣言されたすべてのメンバークラスはこのコレクションから削除されます。
- M が型宣言の場合、S の基本クラス内のすべての非型宣言はセットから削除され、基本型で宣言された S と同じ数の型パラメーターを持つ M のすべての型宣言は、コレクションから削除されます。
- M がメソッドの場合、S の基本クラスで宣言されたメソッド以外のメンバーはすべてこのセットから削除され、S の基本型で宣言された M と同じシグネチャを持つすべてのメソッドがこのコレクションから削除されます。 。

その後、クラスメンバーを通して隠されたインターフェースメンバーがコレクションから削除されます。このステップは、T が型パラメーターであり、T にクラス制約と複数のインターフェース制約がある場合にのみ有効です。コレクション内の各メンバー S.M について、S は M が宣言されている型であり、S がオブジェクトではなくクラス宣言である場合、次のルールが適用されます

- M が定数、フィールド、プロパティ、イベント、列挙型の場合メンバーまたは型宣言を行うと、インターフェイス宣言で宣言されたすべてのメンバーがこのセットから削除されます。
- M がメソッドの場合、インターフェイス型で宣言されたメソッド以外のメンバーはすべてこのセットから削除され、インターフェイスで S として宣言された M の同じシグネチャを持つすべてのメソッドがこのセットから削除されます。

最後に、非表示のメンバーを削除した後、検索の結果が決定されます

- コレクションが型やメソッドではなく単一のメンバーで構成されている場合、このメンバーが検索の結果になります。
- それ以外の場合、セットにメソッドのみが含まれている場合、このメソッドのセットが検索の結果になります。
- それ以外の場合、セットに型宣言のみが含まれている場合、この型宣言のセットはメンバー検索の結果に含まれます。
- そうしないと、ルックアップがあいまいになり、コンパイル時エラーが発生します。
型の場合、インターフェイスの型パラメーターやメンバー検索ではなく、インターフェイス内のメンバー検索は厳密に単一継承であり (継承チェーン内の各インターフェイスには、正確に 0 または 1 つの直接ベース インターフェイスがあります)、検索ルールの効果は派生メンバーのみです。同じ名前と署名を持つ基本クラスのメンバーを非表示にします。この単一継承の検索は非常に明示的です。メンバー検索での曖昧さの可能性は、§13.2.5

20.9.3 単純名

で説明されている多重継承インターフェイスから生じます。

次のコンテンツは §7.5.2 を置き換えることができます。
単純な名前は、識別子と、それに続くオプションの型パラメーターのリストで構成されます。
simple-name: (単純名:)
identifier type-argument-list opt (識別子の型引数リストはオプション)
I または If53db7e3537772cbf9ba1634d2b17fe6 形式の単純名の場合 (I は識別子) If53db7e3537772cbf9ba1634d2b17fe6 という表記は、次のように評価および分類できるオプションの型引数のリストです。

単純名がブロック内に出現し、ブロックのローカル変数宣言スペースに I で指定された名前のローカル変数またはパラメーターが含まれている場合、その単純名はローカル変数またはパラメーターを参照し、変数として分類されます。型引数リストを指定した場合、コンパイル時にエラーが発生します。
単純名がジェネリック メソッド宣言の本文内にあり、その宣言に I で指定された名前の型パラメーターが含まれている場合、単純名はその型パラメーターを参照し、型引数リストのみが指定されている場合は、コンパイル時エラー。
それ以外の場合は、直接囲んでいるクラス、構造体、または列挙型によって宣言されたインスタンス型で始まる型 T の各インスタンスについて、外側の各クラスや構造体によって宣言されているインスタンス型 (存在する場合) を続行します。

- T の宣言に I で指定された型パラメーターが含まれている場合、単純名はその型パラメーターを参照します。型引数リストを指定した場合、コンパイル時にエラーが発生します。
- それ以外の場合、T 内の I のメンバー検索で一致が生成される場合
u T が直接囲んでいるクラスまたは構造体型のインスタンス型であり、検索で 1 つ以上のメソッドが識別される場合、結果は式との一致になります。このメソッド グループに関連付けられています。型引数リストが指定されている場合、それはジェネリック メソッド呼び出しで使用されます (§20.6.3)。
u T が直接囲んでいるクラスまたは構造体型のインスタンス型である場合、ルックアップでインスタンス メンバーが特定され、参照がインスタンス コンストラクター、インスタンス メソッド、またはインスタンス アクセサーのブロック内で発生する場合、結果は同じになります。このように。I メンバーのアクセス形式も同様です。 type 引数を指定した場合、コンパイル時にエラーが発生します。
u それ以外の場合、結果は T.I または T.I 形式のメンバー アクセスと同様になります。この場合、インスタンス メンバーを単純名で参照するとコンパイル時エラーになります。


それ以外の場合、単純な名前が表示される各名前空間を持つ名前空間 N について、エンティティが見つかるまで、各囲みの名前空間 (存在する場合) を続行し、グローバル名前空間で終了するまで、次のステップが評価されます。

- I が N の名前空間の名前で、型引数リストが指定されていない場合、単純名はその名前空間を参照します。
- それ以外の場合、I が、一致する数の型引数を持つ N 内のアクセス可能な型の名前である場合、単純型は、指定された型引数から構築された型を参照します。
u 名前空間宣言に、I で指定された名前に関連付けられた using エイリアス ディレクティブが含まれている場合 (I はインポートされた名前空間または型で、型引数リストが指定されていない場合)、単純名は名前空間または型を参照します。
u それ以外の場合、名前空間宣言の using namespace ディレクティブによってインポートされた名前空間に、型引数の数と一致する I で指定された型が含まれている場合、単純名は指定された型引数から構築された型を参照します。
u それ以外の場合、名前空間宣言の using namespace ディレクティブによってインポートされた名前空間に、型パラメーターの数と一致する I で指定された名前を持つ複数の型が含まれている場合、単純な名前があいまいになり、コンパイル時エラーが発生します
lそれ以外の場合、単純名で指定された名前は未定義となり、コンパイル時エラーが発生します。

20.9.4メンバーアクセス

次のコンテンツは §7.5.4 を置き換えることができます。
メンバー アクセスは、基本的な式または事前定義された型、その後に「.」マーク、識別子、および型引数のオプションのリストで構成されます。
member-access: (メンバーアクセス:)
primary-expression . identifier type-argument-list opt (基本式。識別子の型引数リストはオプション)
predefine-type . identifier type-argument-list opt (事前定義済み)タイプを定義します。識別子のタイプ引数リストはオプションです) 事前定義されたタイプ: 次のいずれか
bool byte char 10進数 double float int long
object short string uint ulong ushort

E.I または E.Ib80345ec0dd305387a5d5e0f070977ca」文字が使用されます (C++ のテンプレート構文と同様)。 Listdd77601bbe5f7db04992ba7b2f8dd60c> のように、構築された型を入れ子にすることもできますが、この構成の使用には微妙な構文の問題がいくつかあります。レクサーはこの構成の最後の 2 つのトークン「>>」を結合します (右)。シフト演算子 ) を使用して、構文で必要な 2 つの「>」タグを生成します。考えられる解決策の 1 つは、2 つの「>>」の間にスペースを入れることですが、これも厄介でわかりにくく、プログラムの単純性はまったく向上しません。
これらの中立的な構造の語彙の単純さを保つために、「>>」および「>>=」マーカーが語彙集から削除され、右シフトおよび右シフト代入生成に置き換えられました。
演算子または句読点: ;
+ - * / % > 6d267e5fab17ea8bc578f9e7e5e1570b = b207bb093495751f3e536c5eb7122819= += -= *= /= %= &= |=
^= 34a2689319230c2c01805e072c161ba7 -shift-assignment: (右シフト代入)
> >=
構文内の他のプロダクションとは異なり、右シフト代入プロダクションのトークンの間にはいかなる種類の文字も使用できません (空間)。

以下のプロダクションは、右シフトまたは右シフト代入を使用して変更されています。
shift-expression: (shift 式:)
additive-expression (追加の式)
shift-expression 4b78e37dce7341935033c7746bd2c94f
ddd0620b42f67e0c3fae74991e3d1d10=
<=

(一般終了)
**************** ************** ****


上記は C# 2.0 仕様 (Generics 6) の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。

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