SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++/CLIで、機能拡張を簡単に実現するフレームワーク「MEF」を試してみた

re-buildなしに機能拡張!

演算子の追加

 では本題、「re-buildなしに機能を拡張」しますか。ソリューションに新しいプロジェクト:CLRクラスライブラリ"ExtendedOpertaions"を起こし、プロジェクト・プロパティの共通プロパティでSimpleCalculatorとSystem.ComponentModel.Compositionの参照を追加します。

 あとはSimpleCalculatorで定義したOperations.cppとまったく同じ体裁で乗算/除算を定義します。

ExtendedOperations.cpp
#include "stdafx.h"

namespace ExtendedOperations {

  using namespace System::ComponentModel::Composition;
  using namespace SimpleCalculator;

  [Export(IOperation::typeid)]
  [ExportMetadata(L"Symbol", L"*")]
  ref class Multiple : IOperation {
  public:
    virtual int Operate(int left, int right) {
      return left * right;
    }
  };

  [Export(IOperation::typeid)]
  [ExportMetadata(L"Symbol", L"/")]
  ref class Subtract : IOperation {
  public: 
    virtual int Operate(int left, int right) {
      return left / right;
    }
  };

}

 ……おっとゴメンナサイ。拡張用アセンブリ(ExtendedOperations.dll)を読み込む部分を忘れてました。SimpleCalculator::CalculatorFormのコンストラクタに追加しなくちゃ。

CalculatorForm::CalculatorForm()
  CalculatorForm::CalculatorForm() {
    InitializeComponent();

    // Import/Export カタログをつくる 
    auto catalog = gcnew AggregateCatalog();
    // まずは自分自身のアセンブリから
    catalog->Catalogs->Add(gcnew AssemblyCatalog(CalculatorForm::typeid->Assembly));

    // そして自分自身の置かれたディレクトリから見つけてくる (追加ここから)
    String^ myLocation = System::IO::Path::GetDirectoryName(
                           System::Reflection::MethodBase::GetCurrentMethod()
                           ->DeclaringType->Assembly->Location);
    catalog->Catalogs->Add(gcnew DirectoryCatalog(myLocation));
    // (追加ここまで)

    // カタログから作られたコンテナを基にImport/Exportを結びつける
    AttributedModelServices::ComposeParts(gcnew CompositionContainer(catalog), this);

    // 得られた演算子(Symbol)をComboBoxに追加する
    for each ( String^ symbol in calculator_->Symbols() ) {
      cbxOpr->Items->Add(symbol);
    }
    cbxOpr->SelectedIndex = 0;
  }

 これにより、SimpleCalculator.exeの置かれたディレクトリにあるアセンブリがすべて読み込まれます。

 ExtendedOperationsをビルドしたのち、SimpleCalculatorを実行するとComboBoxに「*」と「/」が追加されています。

 当然ながら .NETアセンブリであれば、C++/CLIに限らずC#やVBで拡張しても構いません。C#クラスライブラリ・プロジェクトを起こし、

ExtendedOperations.cs
using System.ComponentModel.Composition;
using SimpleCalculator;

namespace ExtendedOperations {

  [Export(typeof(IOperation))]
  [ExportMetadata("Symbol", "%")]
  class Modulus : IOperation {
    public int Operate(int left, int right) {
      return left % right;
    }
  };

  [Export(typeof(IOperation))]
  [ExportMetadata("Symbol", "MIN")]
  class Minimum : IOperation {
    public int Operate(int left, int right) {
      return left < right ? left : right;
    }
  };

  [Export(typeof(IOperation))]
  [ExportMetadata("Symbol", "MAX")]
  class Maxumum : IOperation {
    public int Operate(int left, int right) {
      return left > right ? left : right;
    }
  };
}

 できたDLLをSimpleCalculator.exeと同じディレクトリに置けば……ほらね。

 ……面白いですねぇ、IOerationを定義したAddやSubtractなどは他のどこからも参照されず、ただ定義しExportしただけです。MEFはそれを手掛かりに動的に(実行時に)探し出し、インスタンスを生成してImportした受け皿に乗っけてくれるんですね。アセンブリを配置するだけで機能拡張できるのは、アプリケーションの提供者/利用者の双方に大きなメリットですよね。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7738 2014/06/05 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー