SHOEISHA iD

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

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

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

特集記事

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

re-buildなしに機能拡張!

フォームに組み込む

 もうひといき、ICalculatorの実装Calculatorができたので、これをCalculatorFormに組み込みましょう。

 アトリビュート[Import(ICalculator::typeid)]をつけたICalculator^ calculator_をメンバに追加します。

CalculatorForm.h(抜粋)
#pragma once
#include "Interface.h"

namespace SimpleCalculator {

  public ref class CalculatorForm : public System::Windows::Forms::Form
  {
  public:
    CalculatorForm();

  protected:
    ~CalculatorForm();

  private: System::Windows::Forms::TextBox^  tbxLeft;
  private: System::Windows::Forms::ComboBox^  cbxOpr;
  private: System::Windows::Forms::TextBox^  tbxRight;
  private: System::Windows::Forms::Button^  btnExec;
  private: System::Windows::Forms::Label^  lblResult;

  private:
    System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
....省略
#pragma endregion

  private:
    // 「=」ボタン・クリックのハンドラ
    System::Void btnExec_Click(System::Object^  sender, System::EventArgs^  e);

    [System::ComponentModel::Composition::Import(ICalculator::typeid)]
    ICalculator^ calculator_;
  };

}

 そして実装。

CalculatorForm.cpp
#include "CalculatorForm.h"

using namespace System;
using namespace System::ComponentModel::Composition;
using namespace System::ComponentModel::Composition::Hosting;

namespace SimpleCalculator {

  CalculatorForm::CalculatorForm() {
    InitializeComponent();

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

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

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

  CalculatorForm::~CalculatorForm() {
    if (components) {
      delete components;
    }
  }

  System::Void CalculatorForm::btnExec_Click(System::Object^  sender, System::EventArgs^  e) {
    Int32 left;
    Int32 right;
    // フォームから 左辺/右辺/演算子を取り出し、計算して結果を表示する
    if ( Int32::TryParse(tbxLeft->Text, left) && Int32::TryParse(tbxRight->Text, right) ) {
      try {
        int result = calculator_->Calculate(left, cbxOpr->SelectedItem->ToString(), right);
        lblResult->Text = result.ToString();
      } catch ( Exception^  ) {
        lblResult->Text = L"error";
      }
    } else {
      lblResult->Text = L"?";
    }
  }

}

 ここでのキモはコンストラクタ、これまでに用意した[Export(~)]と[Import(~)]/[ImportMany]とをコンストラクタで(つまり実行時に)結びつけます。

 ExportとImportの一覧表に相当するカタログ:AggregateCatalogを生成し、自分自身が属するアセンブリをAdd()することで、アセンブリ内のExport/Importがカタログに登録されます。

 カタログを引数に生成されたコンテナ:CompositionContainerとthis(=CalculatorForm)とをAttributedModelServices::ComposeParts()に与えると、CalculatorForm内から[Import(~)]が付けられた変数と、対応する(同じtypeidを持った)[Export(~)]の追加クラスをコンテナから探し出して結び付けます。

 このとき、ICalculatorを実装したCalculator内には[ImportMany]なoperations_があるので、さらにこいつに対応する[Export(~)]もコンテナから探し出して……と、再帰的に結び付けてくれます。

 「=」ボタンが押された時のハンドラは簡単。TextBoxとComboBoxからint値2つと演算子を取り出し、operator_に投げて結果を表示すればよし。

 ビルド/実行してみましょう。ComboBoxに「+」と「-」が入っていますね。

次のページ
演算子の追加

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

特集記事連載記事一覧

もっと読む

この記事の著者

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

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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー