interfaceの定義とその実装
それではMEFを使った拡張機能をこしらえましょうか。
まずはinterfaceから。定義するinterfaceは、
- intを2つ与えるとintを返す演算:IOperation
- 演算に付けられた演算子(の名前):IOperationData
- 2つのintと演算子を与えると演算子に応じた演算を行って結果を返す計算機:ICalculator
の3つです。
#ifndef INTERFACE_H_
#define INTERFACE_H_
namespace SimpleCalculator {
public interface class IOperation {
int Operate(int left, int right);
};
public interface class IOperationData {
property System::String^ Symbol { System::String^ get(); }
};
public interface class ICalculator {
int Calculate(int left, System::String^ opr, int right);
System::Collections::Generic::IEnumerable<System::String^>^ Symbols();
};
}
#endif
IOperationの実装は、ひとまず加算:Addと減算:Subtractの2つを用意しましょう。
#include "Interface.h"
using namespace System::ComponentModel::Composition;
namespace SimpleCalculator {
[Export(IOperation::typeid)]
[ExportMetadata(L"Symbol", L"+")]
ref class Add : 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;
}
};
}
ここでのキモは[]で囲まれたアトリビュートです。「Add/SubtractはIOpertationを実装し、不可情報:Symbolを"+"/"-"としてExport(公開)する」ことを表しています。
そしてICalculatorを実装したCalculator:
#include "Interface.h"
using namespace System;
using namespace System::ComponentModel::Composition;
using namespace System::Collections::Generic;
namespace SimpleCalculator {
[Export(ICalculator::typeid)]
ref class Calculator : ICalculator {
private:
[ImportMany]
IEnumerable<System::Lazy<IOperation^, IOperationData^>^>^ operations_;
public:
// Symbolが一致するIOperationを見つけ、実行する
virtual int Calculate(int left, System::String^ operation, int right) {
for each (Lazy<IOperation^, IOperationData^>^ item in operations_) {
if ( item->Metadata->Symbol == operation )
return item->Value->Operate(left, right);
}
throw gcnew NotSupportedException(operation);
}
// Symbolの列挙を返す
virtual IEnumerable<System::String^>^ Symbols() {
auto result = gcnew List<String^>();
for each (Lazy<IOperation^, IOperationData^>^ item in operations_) {
result->Add(item->Metadata->Symbol);
}
return result;
}
};
}
メンバ変数operations_は、IOperationとIOperationDataの組を複数個(演算の数だけ)抱えます。アトリビュート[ImportMany]に注目、MEFはこのアトリビュートが付けられた変数に[Export(IOperation::typeid)]な複数のclassを結び付けてくれます。
メソッドOperate()は、operations_に納められたIOperationとIOperationDataの組を使って演算子に応じたIOperationを見つけて演算を行いますし、Symbols()は登録されている演算子の列挙を返します。
