C#の知識を流用する

概要

この説では、C#や.NETの知識はあるものの、C++やC++/CLIの知識はほとんど無い、という人が
ScenarioModを記述する上においてのノウハウや方法論の1つを提示しています。

ScenarioModは、C++/CLI

ScenarioModはC++/CLIで構成されています。

この意味すところは、「.NET FrameWork」のほとんど全ての資産を簡単に利用できる。
ということです。

今やWindows上の資産や便利な機能は、 .NET FrameWork、「特にC#」を中心に展開されています。

「プロユースのC/C++はわかりません、でもC#なら簡単なGUIアプリなら作れます。」
という方向へと人々の傾向が変化していくであろうことは、疑いの余地がありません。

また、マイクロソフト自身がそのように誘導していますし、
その現象は、Windowsに留まず、Mac、Linuxへと波及してゆくでしょう。
(iPhoneやAndroidのある程度の規模のゲームは、UnityのC#で作られたものが多い)

では、C#の知識を持つ人が、
ScenarioModを記述する上で、その知識を活かすにはどうすれば良いのでしょうか?

ここでは、この点にフォーカスを当ててみます。

便利なツール「C# to C++ Converter」

そこで管理人がお勧めするのが、「C# to C++ Converter」です。

このページ に 「Install C# to C++ Converter」というものがあります。

実はこれが非常に役に立ちます。

このツールは、C#のソースをC++/CLI へと非常に高い精度で変換できます。

PICTURE

完全なエラーのないソースであればあるほど、あるいは、
完成されたVC#のプロジェクトであるほど、正確な変換が可能となりますが、
部分的なソースでも、高い精度での変換が可能です。

下図のように左側に、C#のソースを記述します。

C# to C++ Converter の必須設定

    • 「array」だとエラーになるので「cli::array」になるように設定変更
      VS2015以降では、C++11のarray型とC++/CLIのarrayの名前空間上での優先順位が変化したため、
      arrayのままだと、エラーになりやすくなります。
      以下のようにな設定をして変更しておくことを強くお勧めします。

      PICTURE

      PICTURE

      PICTURE

    • 「 ^」ではなく「^ 」に変更

      PICTURE

      PICTURE

    • C#→C++/CLIへの変換パターン

      PICTURE

  • C++ to C# Converter

    ネイティブではない純粋なC++/CLIで記述されていれば、相当正確に変換されます。
    C++/CLIで記述していたものを一部C#に回したり、元々がC++/CLIのソースだけれど、
    サンプルとしてはC#にしたい場合など、こちらも多目的に便利です。

  • ILSpy

    すでにコンパイル済みのマネージドアセンブリDLL(.NET FrameWork系のDLL)を、
    C#やVB.netの綺麗なソース状態へと戻すツールです。
    すでに詳細が不明なコンパイル済みの.dllを、ソースへと戻して内容を確認等する際に役立ちます。
    また、ソースが公開されていないアセンブリの.NET FrameWorkのバージョンを引き上げるのにも役立ちます。

    ILSpyにより、概ね正確に逆変換が可能ですが、C#のdynamic型については、
    正確には変換が出来ません。

using System;
using System.Collections.Generic;

class Test {
    void MyProc() {
        List<int> mylist = new List<int>();
        mylist.Add(32);
        mylist.Add(25);

        foreach(var i in mylist) {
            Console.WriteLine(i);
        }
    }
}

図のように「C++/CLI」をコンボボックスリストから選択します。

PICTURE

using namespace System;
using namespace System::Collections::Generic;

private ref class Test
{
private:
  void MyProc()
  {
    List<int> ^mylist = gcnew List<int>();
    mylist->Add(32);
    mylist->Add(25);

    for each (auto i in mylist)
    {
      Console::WriteLine(i);
    }
  }
};

これがC++/CLIです。

Linqやdynaimicなど、C#4.0以降に付け加えられた機能を除けば、
C++/CLIは、C#の主要な文法にはほぼ1:1で対応しています、

又、ライブラリは同じものを参照しているわけですから、原則全て利用可能です。

C#の可変長引数なども問題なく変換出来ます。

using System;
using System.Collections.Generic;

class Test {

    int MySumFunc(params int[] values) {
        int Sum = 0;
        foreach(int v in values) {
            Sum += v;
        }
        return Sum;
    }
    void MyProc() {
        MySumFunc(1,2,3,4,5,6);
    }
}

同じように、ツールの左側に入力し、「C++/CLI」を選びなおしてみましょう。
(C++/CLIと見えてるなら、CTRL+Sボタンでも良い)

using namespace System;
using namespace System::Collections::Generic;

private ref class Test
{

private:
    int MySumFunc(... cli::array<int> ^values)
    {
        int Sum = 0;
        for each (int v in values)
        {
            Sum += v;
        }
        return Sum;
    }
    void MyProc()
    {
        MySumFunc(1,2,3,4,5,6);
    }
};

本当にこんな記述が ScenarioModで使えるのでしょうか?

ScenarioModに貼り付けて、
「カスタム::On_プレイヤ担当ターン《メイン画面》() 」メソッド内から呼び出してみましょう。

int MySumFunc(... cli::array<int> ^values)
{
    int Sum = 0;
    for each (int v in values)
    {
        Sum += v;
    }
    return Sum;
}

void カスタム::On_プレイヤ担当ターン《メイン画面》() {
    int sum = MySumFunc(1, 2, 3, 4, 5, 6);
    デバッグ出力 << sum << endl;
}

なんということでしょう、なんという恐ろしさ。

余裕で動作します。

そうです、
これが「共通の.NETというプラットフォーム(CLR)を意識した言語同士だから持つ高い相互変換性」です。

Stringとstringの問題点

しかし、1点問題があります。

それは.NET FrameWorkのString型(C#のstring=System::String)と、
ScenarioModで頻出するstring型(C++のstd::string)は「 全然違う 」ということです。

そこでScenarioModでは、この変換を容易にする仕組みが存在しています。


string nstr = "あああ";
String^ mstr = String←string(nstr);// C++のstring型から.NET FrameWorkのSystem::String型へ

String^ mmsg = "あいう";
string nmsg = string←String(mmsg); // .NET FrameWorkのSystem::String型から C++のstring型へ

この点だけ注意すれば大丈夫です。

存分にC#で得たライブラリの知識を活かして記述できるはずです。