シンプルで不変の値の型がある状況があります。
public struct ImmutableStruct
{
private readonly string _name;
public ImmutableStruct( string name )
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
この値の型のインスタンスをボックス化する場合、通常、ボックス化したものはボックス化解除を行ったときに同じ結果になると予想します。驚いたことに、そうではありません。Reflection を使用すると、ボックスに含まれるデータを再初期化することで、誰かがボックスのメモリを簡単に変更できます。
class Program
{
static void Main( string[] args )
{
object a = new ImmutableStruct( Guid.NewGuid().ToString() );
PrintBox( a );
MutateTheBox( a );
PrintBox( a );;
}
private static void PrintBox( object a )
{
Console.WriteLine( String.Format( "Whats in the box: {0} :: {1}", ((ImmutableStruct)a).Name, a.GetType() ) );
}
private static void MutateTheBox( object a )
{
var ctor = typeof( ImmutableStruct ).GetConstructors().Single();
ctor.Invoke( a, new object[] { Guid.NewGuid().ToString() } );
}
}
出力例:
ボックスの内容: 013b50a4-451e-4ae8-b0ba-73bdcb0dd612 :: ConsoleApplication1.ImmutableStruct ボックスの内容: 176380e4-d8d8-4b8e-a85e-c29d7f09acd0 :: ConsoleApplication1.ImmutableStruct
(実際には、MSDN に、これが意図された動作であることを示す小さなヒントがあります)
なぜ CLR では、ボックス化された (不変の) 値型をこの微妙な方法で変更できるのでしょうか? readonly が保証されないことはわかっています。また、「従来の」リフレクションを使用すると、値のインスタンスを簡単に変更できることもわかっています。ボックスへの参照がコピーされ、突然変異が予期しない場所に現れると、この動作が問題になります。
私が考えていることの 1 つは、System.Reflection APIobject
のみで動作するため、これにより値型で Reflection を使用できるようになることです。ただし、値の型を使用すると、リフレクションはバラバラになりNullable<>
ます (値がない場合は、null にボックス化されます)。ここでの話は何ですか?