良い質問-それが言語設計における興味深い質問である限り。これは、特定の実際のコードに関するものではないため、このサイトにとって理想的な質問ではない可能性があります。
typeof
明示的な演算子なしで型名を式として使用できる言語を設計することは完全に実行可能です。
そのためには、言語にいくつかの追加のルールと説明を追加する必要があります。たとえば、次のようにしたとします。
enum Color { Red }
class Square
{
Color Color { get; set; }
void M()
{
Type t = Color.GetType();
今日のC#では、これは明確に、プロパティColorのgetterを呼び出し、結果に対してGetTypeを呼び出すことを意味します。(理由の説明については、仕様の「カラーカラールール」セクションを参照してください。)提案された世界では、これが意味する可能性のある3つのことがあります。
- Colorのゲッターを呼び出し、結果に対してGetTypeを呼び出し、ColorのTypeオブジェクトをtに割り当てます。
- Colorは、タイプColorのTypeオブジェクトになります。そのタイプでGetTypeを呼び出し、System.TypeのTypeオブジェクトをtに割り当てます。
- ColorはタイプColorを参照し、GetTypeは非静的メソッドを参照します。これは非静的メンバーへの静的呼び出しであるため、これはエラーです。
式のColorが型を意味するのか、型オブジェクトを作成するのかが明確になるように、仕様を明確にする必要があります。したがって、提案された機能は、対処しなければならないわずかなあいまいさを追加しますが、それは完全に実行可能です。言語設計者は、合理的なルールを考え出すことができます。
通常はコンパイル時分析の一部である言語要素を、同じプログラム内のコードで操作できるオブジェクトを作成するコードとして解釈できるようにする言語は、同像性言語と呼ばれます。C#は、C#3以前は非常に非ホモイコニックな言語でした。式ツリーにより、C#ははるかに同像性になりました。C#3では、ラムダをプログラム要素として扱い、ラムダ本体のアクションを実行するメソッドを生成するために使用できますが、ラムダからラムダの本体を表すオブジェクトへの同像変換もサポートしています。
最も同像性のある言語の1つはLispです。Lispはリストを操作し、Lispプログラム自体はリストとして考えることができます。実行時に、コードとしてではなくオブジェクトとして引用および操作できます。したがって、ここでも、言語設計に関する古いジョークの真実がわかります。すべての言語設計者は、最終的にLispをひどく再発明します。
私は逸脱します。あなたの質問は本質的に次のとおりです:C#はタイプ名に関して多かれ少なかれ同像性である必要がありますか?タイプ名に1つの意味(コンパイル時ディレクティブ)がある場合、次のようなコンテキストで
Foo x = new Foo();
object o = new List<Foo>[] {};
Foo.StaticMethod();
そして、非常に異なる意味を持っています-他のコンテキストで実行時に検査できるオブジェクトの構築として:
object t = Foo; // Assign a Type object to t.
?
そのような言語をデザインすることは確かに可能ですが、私はそれがあまり好きではありません。そこにオペレーターが明確に「ねえ、私たちは通常コンパイル時の要素を同像性の方法で使用している」とはっきりと呼びかけていなければ、混乱を招く可能性があります。C#3以前は、他の同像性言語機能はありませんでした。そのため、型オブジェクトを生成する型または式の両方として型を使用できるということだけを持っているのは少し奇妙に思えます。また、一部の式では、特定の単純な名前が「コンパイル時にこのタイプを使用している」または「オブジェクトを作成したい」という意味であるかどうかが不明な場合があります。
明示的なタイプの演算子を使用すると、これらすべての懸念が軽減されます。タイプがホモアイコン的に使用されている場合は明確であり、読者には非常に明確です。
あなたの質問に関する非常に具体的なポイントに対処するには:
タイプSystem.Type..のプロパティにタイプを割り当てようとする場合
C#には、一般的に、割り当てにのみ適用される特別なルールはありません。式の意味は通常、式が使用されているコンテキストに訴えることなく決定されます。私たちが言うとき:
x = y;
一般的に、「ああ、yがxに割り当てられており、xがタイプXであることを知っているので、その情報をyの分析に使用します」とは言いません。むしろ、分析は内側から外側に行きます。yが何を意味するかを理解し、それがXと互換性があるかどうかを判断します。
このルールの例外はもちろんラムダです。ラムダは「ターゲット」タイプを考慮に入れます。これは、ターゲットタイプを使用して、暗黙的に型指定されたラムダのタイプを推測できるためです。これらのルールを正しく理解することは非常に複雑でした。
より一般的には、代入式を特別なものにすることはお勧めできません。値を変数に割り当てる方法はたくさんあります。
M(x); // x is assigned to a formal
q = new [] { x }; // x is assigned to the first element of an array
y = new Y() { X = x }; // x is assigned to a property of Y.
これらすべての割り当てのルールに一貫性を持たせる必要があります。式が「私は型オブジェクトです」を意味する場合、それは、代入の右側としてだけでなく、その式が現れる可能性のあるすべてのコンテキストで意味する必要があります。