日々拝読している akiramei さんの 匣の向こう側 - あまりに.NETな の記事で、Genericsとunsafe というのがあったのですが。
Marshal.UnsafeAddrOfPinnedArrayElement
これが勝利の鍵だ。
と言う結論ですが、これ間違いです。
MSDN の解説には次のように書かれています。
配列は、GCHandle を使用して pin を実行してあります。パフォーマンスを高めるため、このメソッドは渡された配列に対して一切の検証を行いません。この結果、予期しない動作につながることがあります。
分かりづらい文章ですね。原文だと極めて明快です。
The array must be pinned using a GCHandle before it is passed to this method.
このメソッドによって配列が自動的に固定されることはありません。配列を固定していない場合、このメソッドを呼び出した後に GC が起動して配列のアドレスが移動し、メソッドで取得したアドレスが無効になる可能性があります。
英文通り、事前に GCHandle.Alloc(object, GCHandleType.Pinned) で固定しなければいけません。で、GCHandle.Alloc したなら GCHandle.AddrOfPinnedObject メソッドを使うことで先頭アドレスが取得できます。
Alloc の第一引数はプリミティブなメンバしか含まない構造体でなければなりませんが、これの評価は実行時にされるので Generics でも問題なく使えます。