web-dev-qa-db-ja.com

.NETフレームワークに、ファーストクラスの型としてのクラスの概念がないのはなぜですか?

C#と.NETフレームワークは、本質的に「DelphiはJavaのように書き直された」として始まり、Delphiの背後にあるチーフ開発者であるAnders Hejlsbergによって設計されたという歴史に詳しい人にはよく知られています。それ以来、状況はかなり分岐していますが、初期の類似点は非常に明白だったため、一部の 。NETが実際にはBorlandの製品であったという深刻な推測もありました。

しかし、私は最近いくつかの.NETのことを調べており、Delphiの最も興味深い便利な機能の1つが完全に欠落しているようです:ファーストクラスのデータ型としてのクラスの概念。 TClass型は、.NETのType型と同様に、クラスへの参照を表します。しかし、.NETがリフレクションにTypeを使用する場合、DelphiはTClassを言語の非常に重要な組み込み部分として使用します。クラスサブタイプ変数や仮想クラスメソッドなど、単純に存在しない、存在しないさまざまな便利なイディオムが可能になります。

すべてのOO言語には仮想メソッドがあり、異なるクラスがメソッドの同じ基本概念を異なる方法で実装し、オブジェクトインスタンスの実際のタイプに基づいて実行時に適切なメソッドが呼び出されますDelphiはこの概念をクラスに拡張します。TClass参照が特定のクラスサブタイプとして定義されている場合(つまり、class of TMyClassは、変数がTMyClassから継承するすべてのクラス参照を受け入れることを意味しますが、クラススコープの仮想メソッドが接続されている階層外のものではなく、クラスの実際のタイプを使用してインスタンスなしで呼び出すことができます。たとえば、このパターンをコンストラクターに適用すると、ファクトリー実装が簡単になります。

.NETには同等のものはないようです。クラス参照(特に仮想コンストラクターや他の仮想クラスメソッド!)と同じくらい便利ですが、除外された理由について誰かが何か言いましたか?

具体的な例

フォームの逆シリアル化

Delphi VCLは、フォームをDFM形式で保存します。これは、コンポーネント階層を記述するためのDSLです。フォームリーダーがDFMデータを解析すると、次のように記述されたオブジェクト全体で実行されます。

object Name: ClassName
   property = value
   property = value
   ...
   object SubObjectName: ClassName
      ...
   end
end

ここで興味深いのは、ClassNameの部分です。各コンポーネントクラスは、TClassinitialization時にコンポーネントストリーミングシステムに登録します(わずかに異なる静的コンストラクターを考えてください。起動時にすぐに発生することが保証されています。)これにより、各クラスが文字列に登録されます->クラス名をキーとするTClassハッシュマップ。

各コンポーネントはTComponentから派生し、単一の引数Owner: TComponentを受け取る仮想コンストラクターがあります。どのコンポーネントもこのコンストラクタをオーバーライドして、独自の初期化を提供できます。 DFMリーダーはクラス名を読み取るときに、前述のハッシュマップで名前を検索し、対応するクラス参照を取得します(または、そこにない場合は例外を発生させます)、仮想TComponentコンストラクターを呼び出します。これは、登録関数がTComponentの下位クラスに必要なクラス参照を受け取り、最終的に適切な型のオブジェクトになるためです。

これがないと、WinFormsの同等機能は...まあ...率直に言って大きな混乱で、新しい.NET言語が独自のフォームを完全に再実装する必要がある(逆)シリアル化です。これについて考えると、これは少しショックです。 CLRを使用する目的はすべて、複数の言語で同じ基本インフラストラクチャを使用できるようにすることなので、DFMスタイルのシステムは完全に理にかなっています。

拡張性

私が書いたイメージマネージャークラス は、データソース(イメージファイルへのパスなど)を提供し、コレクションにない名前を取得しようとした場合に新しいイメージオブジェクトを自動的にロードできますが、データソースで利用可能です。作成される新しいオブジェクトのクラスを表す、class ofとして型付けされたクラス変数を持つ基本イメージクラスがあります。デフォルトで提供されていますが、特別な目的で新しいイメージを作成する場合、イメージをさまざまな方法で設定する必要があるという点がいくつかあります。 (アルファチャネルなしで作成する、PNGファイルから特別なメタデータを取得してスプライトサイズを指定するなど)

これは、大量の構成コードを記述し、最終的に新しいオブジェクトを作成する可能性のあるすべてのメソッドに特別なオプションを渡すことによって行うことができます...または、仮想メソッドをオーバーライドする基本イメージクラスのサブクラスを作成することもできます。問題のアスペクトが構成され、try/finallyブロックを使用して、必要に応じて「デフォルトクラス」プロパティを一時的に置き換え、それを復元します。クラス参照変数を使用してこれを行うのははるかに簡単であり、代わりにジェネリックスを使用して実行できるものではありません。

20
Mason Wheeler

.NET(CLR)は、Microsoftのコンポーネントオブジェクトモデル(COM)の第3世代であり、初期の頃は「COM +ランタイム」と呼ばれていました。 Microsoft Visual BasicおよびCOM/ActiveXコントロール市場は、Borland Delphiよりも、特定のCLRアーキテクチャの互換性の選択に大きな影響を与えてきました。 (確かに、DelphiがActiveXコントロールを採用したことは確かにActiveXエコシステムを成長させるのに役立ちましたが、COM/ActiveXはDelphiの前に存在しました)

COMのアーキテクチャはC(C++ではなく)で作成され、クラスではなくインターフェイスに重点を置いていました。さらに、サポートされているオブジェクト構成。つまり、COMオブジェクトは実際には複数の異なるオブジェクトで構成され、IUnknownインターフェイスがそれらをリンクします。しかし、IUnknownは、可能な限り言語に依存しないように設計されたCOMオブジェクトの作成には役割がありませんでした。オブジェクトの作成は通常、IClassFactoryによって処理され、リフレクションはITypeLibraryおよび関連するインターフェースによって処理されました。この懸念の分離は、実装言語とは無関係であり、各コアCOMインターフェイスの機能は最小限に抑えられ、直交していました。

したがって、COMおよびActiveXコントロールの人気の結果として、.NETアーキテクチャは、COM IUnknown、IClassFactory、およびITypeLibraryをサポートするように構築されました。 COMでは、これらのインターフェイスは必ずしも同じオブジェクト上にあるとは限らなかったため、これらをまとめることは必ずしも意味がありませんでした。

5
Burt_Harris