具象化とは、一般に(コンピューターサイエンスの範囲外で)「何かを現実にする」ことを意味します。
プログラミングでは、言語自体でそれに関する情報にアクセスできれば、何かが具体化されます。
C#が具体化していて具体化していない、完全に非ジェネリック関連の2つの例について、メソッドとメモリアクセスを見てみましょう。
オブジェクト指向言語には一般にメソッドがあります(クラスにバインドされていませんが、類似した関数を持たないものも多数あります)。そのため、そのような言語でメソッドを定義したり、メソッドを呼び出したり、オーバーライドしたりすることができます。このようなすべての言語で、メソッド自体をプログラムへのデータとして実際に処理できるわけではありません。C#(実際には、C#ではなく.NET)を使用すると、MethodInfo
、メソッドを表すオブジェクトため、C#ではメソッドが具体化されます。C#のメソッドは「ファーストクラスオブジェクト」です。
すべての実用的な言語には、コンピュータのメモリにアクセスする手段がいくつかあります。Cのような低レベル言語では、コンピューターが使用する数値アドレス間のマッピングを直接処理できるため、int* ptr = (int*) 0xA000000; *ptr = 42;
(0xA000000
この方法でメモリアドレスにアクセスすることが疑われる正当な理由がある限り)t何かを爆破する)。C#ではこれは合理的ではありません(.NETで強制することはできますが、.NETのメモリ管理では、移動することはあまり役に立ちません)。C#には具体化されたメモリアドレスはありません。
したがって、リファイドとは「現実化」を意味するので、「具体化された型」は、問題の言語で「話す」ことができる型です。
ジェネリックスでは、これは2つのことを意味します。
一つは、あるList<string>
だけのようなタイプであるstring
かint
です。そのタイプを比較して名前を取得し、それについて問い合わせることができます。
Console.WriteLine(typeof(List<string>).FullName); // System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Console.WriteLine(typeof(List<string>) == (42).GetType()); // False
Console.WriteLine(typeof(List<string>) == Enumerable.Range(0, 1).Select(i => i.ToString()).ToList().GetType()); // True
Console.WriteLine(typeof(List<string>).GenericTypeArguments[0] == typeof(string)); // True
この結果、メソッド自体の中でジェネリックメソッド(またはジェネリッククラスのメソッド)のパラメーターの型について「話す」ことができます。
public static void DescribeType<T>(T element)
{
Console.WriteLine(typeof(T).FullName);
}
public static void Main()
{
DescribeType(42); // System.Int32
DescribeType(42L); // System.Int64
DescribeType(DateTime.UtcNow); // System.DateTime
}
原則として、これを過度に行うことは「臭い」ですが、多くの有用なケースがあります。たとえば、次を見てください。
public static TSource Min<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default(TSource);
if (value == null)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
do
{
if (!e.MoveNext()) return value;
value = e.Current;
} while (value == null);
while (e.MoveNext())
{
TSource x = e.Current;
if (x != null && comparer.Compare(x, value) < 0) value = x;
}
}
}
else
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext()) throw Error.NoElements();
value = e.Current;
while (e.MoveNext())
{
TSource x = e.Current;
if (comparer.Compare(x, value) < 0) value = x;
}
}
}
return value;
}
これは、のタイプ間の比較の多くを行わないTSource
と、異なる動作のための様々なタイプ(あなたがすべてでジェネリックを使用していてはならないことが一般的に記号)が、それは可能なタイプのためのコードパスの間の分割を行いますnull
(返さなければならないnull
場合要素が見つからないため、比較対象の要素の1つがである場合に最小値を見つけるために比較を行ってはなりませんnull
)できないタイプのコードパスnull
(要素が見つからない場合はスローする必要があり、null
要素の可能性を心配する必要はありません))。
のでTSource
メソッド内で「本物」である、この比較は、ランタイムまたはjitting時のいずれか行うことができます(一般的に時間をjitting、確かに上記の場合は、jitting時にそうして取られていないパスのマシンコードを生成しない)、我々は持っていますケースごとにメソッドの個別の「実際の」バージョン。(最適化として、マシンコードは異なる参照型の型パラメーターのさまざまなメソッドで共有されます。これは、これに影響を与えずに実行できるため、ジッターされるマシンコードの量を減らすことができるためです)。
C#で私たちは当たり前のこの具体化を取るので、あなたはまた、Javaの対処しない限り、(これは、C#でジェネリック型の具体化について話をするのが一般的ではありません。すべてのタイプが具体化されているのJavaは、非ジェネリック型はと呼ばれている。具体化そのため、それらとジェネリック型の違いです)。