COMの制限を考慮して.NETライブラリを作成するか、.NETライブラリを相互運用から分離する方が良いですか


9

私はこの興味深い記事に出くわしました:CodeProjectでのCOM相互運用性が好きになりました。

著者は、.NETライブラリの美しさを損なうため、.NETライブラリにCOM-ityを必要としないと主張しています。代わりに、.NETライブラリをCOMに公開する個別の相互運用ライブラリを作成します。この相互運用ライブラリは、COMがパラメーター、オーバーロードメソッド、ジェネリックス、継承、静的メソッドなどのコンストラクターをサポートしていないという事実を処理します。

そして、それは非常に斬新なことだと思いますが、それだけでプロジェクトを完成させるのではないですか?

  • 次に、.NETライブラリとInteropライブラリを単体テストする必要があります。
  • 次に、美しい.NETライブラリを回避してCOMに公開する方法を理解するために時間を費やす必要があります。
  • クラス数を効果的に2倍または3倍にする必要があります。

COMと非COMの両方をサポートするためにライブラリが必要かどうかは確かに理解できます。ただし、COMのみを使用する場合、この種の設計は私には見られない利点をもたらしますか?C#言語の利点しか得られませんか?

または、ラッパーを提供することでライブラリのバージョン管理を容易にしますか?COMを使用する必要がないため、単体テストの実行が速くなりますか?


2
つまり、実際のコードをより良い/よりクリーンにするために便利なツールを使用できることに加えて、そして、その(おそらくレガシー)COM関連の明確な移行パスを提供していますか?
Telastyn 2015年

3
これは、名前空間全体に渡る大きなファサードパターンのようなものです。.NET機能を使用したいがOLEオートメーションが本当に必要な場合は、このように整理するのが賢明だと思います。COMラッパーは基本的に、モダンな(不変?ジェネリック?)イディオムを、パラメーターのないコンストラクター、非常に変更可能なオブジェクト、およびジェネリックリストのSAFEARRAYを使用して、古いCOMオブジェクトに変換します。他の.NETコンポーネントをサポートしている場合、または新しいスタイルを完全に愛している場合、これは理にかなっています。COMのみをサポートしている場合は、VB6(32ビット)で全体を記述し、イディオムを1つだけ保持してみませんか?
マイクはモニカをサポート

3
@MasonWheeler:6か月以上経過したすべてのソフトウェアが「レガシー」であるのと同じ方法で非推奨になりました。
whatsisname 2015年

2
@MasonWheeler COMは、プロセス外のものを制御するための最良の選択であるため、いくらの人々(Microsoft内の一部のグループを含む)が望んでも減価償却できません。
マイクはモニカをサポート

2
@マイク、私は実際にVB6プロジェクトをC#.NETに移植することを検討しています。私たちが使用するユーザー向けのAPIは非常に単純ですが、舞台裏のコードは現状のままでは維持できません。ライブラリの大部分をC#.NETで実装し、さまざまなクラスとやり取りするシンプルなAPIを提供する相互運用ファサードを提供したいと思っています。
robodude666 2015年

回答:


7

ただし、COMのみを使用する場合、この種の設計は私には見られない利点をもたらしますか?

あなたの質問のこのスニペットは、ここにあなたの設計上の決定の最も重要な部分と、答えは(いつものように)で、それが依存します

COM Interop経由でのみライブラリを使用する場合は、これを考慮してシステム全体を設計する必要があります。行数を3倍にする理由はありません。システムのLoCが多ければ多いほど、システムの欠陥も多くなります。したがって、COM互換機能のみを使用するようにシステムを設計する必要があります。

ただし、.Netライブラリの使用をCOMに制限する正当な理由は考えられません。他の.Netコードでアセンブリを使用したくないのなぜですか?この方法で自分を制限することはほとんど意味がありません。

私はこれについてある程度の経験があるので、それをどのように処理したかを共有します。その確かに理想的ではありません。私はいくつかのトレードオフをしました。私は、新しい.Netイディオムと互換性のないCOMクラス(実際にはインターフェイス)のファサードのみを使用しています。それ以外の場合は、.Netインターフェイスを直接COMに公開します。これは基本的に、ジェネリックを使用するすべてのインターフェースにファサードを使用することを意味します。ジェネリックスは私が遭遇した唯一の互換性のないものです。残念ながら、これはを返すすべてのファサードを意味しますがIEnumerable<T>、これはかなり一般的です。

ただし、ファサードクラスは.Netクラスを継承し、特定のInteropインターフェイスを実装するため、これは見かけほど悪くはありません。このようなもの。

namespace Company.Product.Feature
{
    public class MyClass : INetInterface 
    {
        // lots of code
    }
}

namespace Company.Product.Interop
{
    public class MyClass : Feature.MyClass, IComInterface
    {
        // over ride only the  incompatible properties/methods
    }
}

これにより、重複コードを最小限に抑え、COMインターフェースを「意図しない」変更から保護します。コアクラス/インターフェースが変更されると、アダプタークラスはより多くのメソッドをオーバーライドする必要があります(または、インターフェースを壊してメジャーバージョン番号を上げる必要があります)。一方、InteropコードのすべてがInterop名前空間に保存されるわけではないため、ファイルの整理が混乱する可能性があります。私が言ったように、それはトレードオフです。

この完全な例については、私のリポジトリのSourceControlおよびInteropフォルダーを参照してください。ISourceControlProviderそしてGitProvider特に対象としています。


返信@RubberDuckをありがとう!数日前、RubberDuckプロジェクトに出会いました。コードを読むのはとても興味深いものでした。IEnumerableVBA に合格できますか?また、Rubberduck.Interop.GitProviderCOMでサポートされていない場合に、なぜパラメーター化されたコンストラクターを定義したのですか?
robodude666 2015

はい、IEnumerableCOM を通過させることができますが、それは古い非汎用バージョンでなければなりません。コンストラクタについては、をご覧くださいSourceControlClassFactory。基本的には、そのctorのパラメーターを必要としないクラスのインスタンスを初期化し、それを使用してAPIのクラスの新しいインスタンスにアクセスすることによって、それを偽造します。
RubberDuck 2015

ComVisible(true)COMがサポートしていないクラス/インターフェイスで定義されているものはすべて単に「無視」されていると思いますか?また、複数の名前空間で定義された同じ名前のクラスがあるProgId場合、それらを複数公開する場合に一意にする必要があると思いますか?
robodude666 2015

はい。その通りであり、staticメソッドは無視されます。VB6に相当するものがあるかどうかを確認しようとしていVB_PredeclaredIdます。デフォルトのインスタンスを作成できる可能があると思います。
RubberDuck 2015

7

.NETライブラリの美しさを奪います

その作者は、目を覚ますスラップが必要です。あらゆるプロフェッショナルプロジェクトの目標は、人々が使用したい実用的なソフトウェアを作成することです。美についてのあらゆる見当違いの理想はその後ずっと来ます。それが彼らの唯一の理由である場合、著者はすべての信頼性を失っています。

クラスをcom-visibleとしてマークできること、およびCOMを介して.NETコードと通信できることは、非常に便利です。美容のための生産性への大きな利益を捨てることは非常識です。

ただし、COMで物事を機能させるにはいくつかのトレードオフが必要です。引数のないコンストラクターが必要なこともその1つであり、他のいくつかはあなたが言及したものです。いずれにせよ、これらの機能を使用していない場合、または使用しなくても害がない場合は、COMと非COMに同じクラスを使用することで、多くの作業を節約できます。

一方、COMクライアントが劇的に異なるインターフェイスを期待している場合、依存関係または.NETクラスで扱いにくい他の制限がある場合、または.NETクラスを大幅に変更する予定であり、COMを後方に維持する必要がある場合互換性を確保するために、Interopクラスを作成して、そのギャップを埋めてください。

しかし、「美」については考えないでください。.NETを介してCOMを公開できることは、作業を節約するためのものです。自分のためにもっと仕事を作成しないでください。


+1。私はブラックボックスの黒いボタンの美しさを気に入っていますが、実用性は非常に重要です。
gbjbaanb 2015年

実際、この議論に「美」という言葉を取り入れた人は目覚めの平手打ちを必要とするかもしれませんが、それは他の記事の著者ではありませんでした。
Doc Brown

2
余談ですが、現在のコンストラクターが引数を必要とする場合は、既存のインターフェイス/ APIを再設計するのではなく、COMコンポーネントにクラスファクトリを提供するのが最善です。
RubberDuck、2015

1
ファクトリを「GlobalMultiUse」クラスとして公開することは可能ですか?それでSet oObject = MyCOMInterop.NewMyClass()、最初に新しいFactoryオブジェクトをインスタンス化する必要なしにそれを行うことができますか?
robodude666 2015

それはいまいましい質問です@ robodude666。あなたがそれを言ったので、私そう願っています。
RubberDuck、2015

3

まあ、公平に言うと、その記事の元の著者は彼の記事のどこにも「美」という言葉を使用していませんでした。自分自身。

私がその記事を理解している限り、.NETライブラリはすでに存在し、COMを考慮せずに作成されました。おそらく、ライブラリが作成された時点では、COMをサポートする必要がないためです。

その後、COMをサポートするという追加の要件が導入されました。このような状況に直面した場合、次の2つのオプションがあります。

  • 元のlibを再設計して、COM相互運用機能と互換性があるようにします(物を壊す危険があります)。

  • 元の作業ライブラリをほとんどそのままにして、代わりに「ラッパー」(または「アダプタ」)の機能を使用して別のアセンブリを作成します

ラッパーまたはアダプターの作成は、よく知られている設計パターン(またはこの場合は、アーキテクチャー・パターン)であり、長所と短所もよく知られています。それに対する一つの議論はより良い「懸念の分離」であり、それは美しさとは何の関係もありません。

あなたの懸念に

次に、.NETライブラリとInteropライブラリを単体テストする必要があります。

再設計によってCOMインターフェイスを既存の.NETライブラリに導入する場合は、そのインターフェイスもテストする必要があります。手動で作成されたアダプターを導入するには、インターフェースが機能する追加のテストが必要になる場合がありますが、libのコアビジネス機能のすべての単体テストをコピーする必要はありません。libへの単なるインターフェースの1つであることを忘れないでください。

次に、美しい.NETライブラリを回避してCOMに公開する方法を理解するために時間を費やす必要があります。

元のライブラリを再設計する必要がある場合は、それも理解する必要があり、さらに多くの作業が必要になると思います。

クラス数を効果的に2倍または3倍にする必要があります。

元のライブラリの一部のクラスの一部である、パブリックCOMインターフェイスを介して公開されるクラスのみ。

あなたが言及した別の状況では、最初から一流の市民としてCOMをサポートする必要があることがすでにわかっている場合、私はあなたが正しいと思います:個別のアダプターlibを追加する手間を省き、 COMを直接サポートする.NET lib。


(+1)ただし、「...少数の...元のライブラリである必要があります」となる場合もあります。「クラスライブラリスタイル」で設計されたプロジェクトには多くの種類があり、1つのクラスは公に見える1つの目的に相当し、そのクラスは興味深い機能を生み出すために構成されます。その場合、.NETクラス数とCOM相互運用クラス数の間に1対1のマッピングが存在する可能性があります。
rwong 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.