読者です 読者をやめる 読者になる 読者になる

納得いかないこと

C++/CLI C#

最近プログラムを書いていてちょっと納得いかなかったことをいくつか。

enumの型指定

C#で、これはOKですが、

enum Hoge : int 
{
    Fuga, Piyo
}

全く同じはずのこれはコンパイルできません。

enum Hoge : Int32 
{
    Fuga, Piyo
}

個人的に、P/Invokeの際に限っては明示的に何ビットの型か示せるほうが良いのですが、残念。というか、わざわざ型のバイト数を細かく気にするのなんてP/Invokeの時ぐらいしかないので、ほんと残念。

なお、C++/CLIではintといった予約語の方でもSystem::Int32という書き方でもどちらでもコンパイルは通ります。

enum class Hoge1 : int 
{
    Fuga, Piyo
};
enum class Hoge2 : Int32 
{
    Fuga, Piyo
};

C++/CLIではcharはByteだったりlongはInt32だったりしてハマる恐れがあるので、予約語のほうは出来るだけ使わず、常にByteとかInt32といったように書いていたほうが安全だと思われます。

ジェネリッククラスでDllImport

C#で、以下のコードは、実行時にエラーとなります。

class Program
{
    class Hoge<T>
    {
        [DllImport("kernel32.dll")]
        extern static bool Beep(UInt32 dwFreq, UInt32 dwDuration);
    }
    static void Main(string[] args) 
    {
        var hoge = new Hoge<object>();
    }
}

TypeLoadException 「ジェネリック メソッドまたはジェネリック クラスのメソッドは内部呼び出し、PInvoke であるか、または COM インポート クラスで定義されています。」というなかなか意味不明なメッセージが出ます。

何となく原因はわかるものの不勉強ゆえに説明はできそうにありません。ひとまず以下のようにして非ジェネリック版のクラスから継承させて切り抜けるか、もしくはDllImport専用のstaticクラスでも別に作っておくぐらいしか手はなさそうです。

class Hoge 
{
    [DllImport("kernel32.dll")]
    protected extern static bool Beep(UInt32 dwFreq, UInt32 dwDuration);
}

class Hoge<T> : Hoge 
{
}

C++/CLIジェネリッククラスと非ジェネリッククラスで同じ名前が付けられない

前節の非ジェネリッククラスから継承させる手法をC++/CLIでやってみたところ、「同名のクラスが既に定義されてます」とエラーが出てかなり愕然としました。

ref class Hoge 
{
};

generic<typename T>
ref class Hoge : public Hoge 
{
};

今のところ解決策は見いだせず、別な名前にして凌いでいます。