marshal_as<>

 久しぶりに #using の文字列操作を修正して思ったのですが、VS2008 で追加された marshal_as って別に文字列を変換するための機能に止まらないですよね。
 どちらかというと、ネイティブとマネージドの互換ルールの記述スタイルをこのような形で用意しましょうというルール付けだったりするわけです。

MSDN2 マーシャリング・ライブラリの拡張
http://msdn.microsoft.com/ja-jp/library/bb531313.aspx


・クラス宣言

struct Natives
{
    std::string PlaceName;
    double X;
    double Y;
    double Z;
};

ref class Managed
{
private:
    double _x, _y, _z;
    String^ _placeName;
public:
    Managed() {}

    void Set(std::string name, double x, double y, double z)
    {
        _placeName = marshal_as<String^>(name);
        this->_x = x;
        this->_y = y;
        this->_z = z;
    }

    property double X
    {
        double get()
        {
            return this->_x;
        }
    }
    property double Y
    {
        double get()
        {
            return this->_y;
        }
    }
    property double Z
    {
        double get()
        {
            return this->_z;
        }
    }

    property String^ Name
    {
        String^ get()
        {
            return this->_placeName;
        }
    }
};

 これを相互変換するヘッダを用意するわけです。

・自前の marshal ヘッダ marshal_place.h

namespace msclr
{
    namespace interop
    {
        template&lt;&gt;
        inline Managed^ marshal_as<Managed^, Natives> (const Natives& from)
        {
            Managed^ mgd = gcnew Managed;
            mgd->Set(from.Name, from.X, from.Y, from.Z);
            return mgd;
        }

        template<>
        ref class context_node&lt;Natives*, Managed^&gt; : public context_node_base
        {
        private:
            Natives* toPtr;

        public:
            context_node(Natives*& toObject, Managed^ fromObject)
            {
                toPtr = NULL;
                toPtr = new Native();
                toPtr->PlaceName = marshal_as<std::string>(fromObject);
                toPtr->X = fromObject->X;
                toPtr->Y = fromObject->Y;
                toPtr->Z = fromObject->Z;
                toObject = toPtr;
            }

            ~context_node()
            {
                this->!context_node();
            }
        protected:
            !context_node()
            {
                if ( toPtr != NULL )
                {
                    delete toPtr;
                    toPtr = NULL;
                }
            }
        };
    }
}

 このヘッダを用意しておくと、

#include &lt;marshal_place.h&gt;

//
struct Natives nat;
Managed^ mgt = marshal_as<Managed^>(nat);

// 
Managed^ mgt = gcnew Managed;
marshal_context ctx;
struct Natives* nat = ctx.marshal_as<Natives*)(mgt);

と言う形で、相互にやりとりできるわけです。

 ちょっとした手間ですが、相互やりとりが多い場合にはコードが綺麗になりますね。