各エントリに定数でアクセスできる固定サイズの数値コレクションがたくさんあります。当然、これは配列と列挙型を指しているようです:
enum StatType {
Foo = 0,
Bar
// ...
}
float[] stats = new float[...];
stats[StatType.Foo] = 1.23f;
もちろん、これに関する問題は、列挙型を使用してキャストなしで配列にインデックスを付けることができないことです (ただし、コンパイルされた IL はプレーンな int を使用しています)。したがって、これをあちこちに書く必要があります:
stats[(int)StatType.foo] = 1.23f;
キャストせずに同じ簡単な構文を使用する方法を見つけようとしましたが、まだ完全な解決策は見つかりませんでした。配列よりも約 320 倍遅いことがわかったので、辞書の使用は問題外のようです。また、列挙型をインデックスとして配列のジェネリック クラスを作成しようとしました。
public sealed class EnumArray<T>
{
private T[] array;
public EnumArray(int size)
{
array = new T[size];
}
// slow!
public T this[Enum idx]
{
get { return array[(int)(object)idx]; }
set { array[(int)(object)idx] = value; }
}
}
または、列挙型を指定する 2 番目のジェネリック パラメーターを持つバリアントですらあります。これは私が望むものに非常に近いですが、問題は、特定されていない列挙型 (ジェネリック パラメーターまたはボックス化された型の列挙型) を int にキャストできないことです。代わりに、最初にオブジェクトへのキャストでボックス化し、次にキャストする必要があります。これは機能しますが、かなり遅いです。インデクサー用に生成された IL は次のようになっていることがわかりました。
.method public hidebysig specialname instance !T get_Item(!E idx) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld !0[] EnumArray`2<!T, !E>::array
L_0006: ldarg.1
L_0007: box !E
L_000c: unbox.any int32
L_0011: ldelem.any !T
L_0016: ret
}
ご覧のとおり、不要なボックスとアンボックスの説明があります。バイナリからそれらを取り除くと、コードは正常に機能し、純粋な配列アクセスよりも少し遅くなります。
この問題を簡単に克服する方法はありますか? それとももっと良い方法ですか?このようなインデクサー メソッドにカスタム属性のタグを付けて、コンパイル後にこれら 2 つの命令を削除することも可能だと思います。それに適したライブラリは何でしょうか?もしかしてモノ・セシル?
もちろん、列挙型を削除して、次のように定数を使用する可能性は常にあります。
static class StatType {
public const int Foo = 0;
public const int Bar = 1;
public const int End = 2;
}
配列に直接アクセスできるため、これが最速の方法かもしれません。