私はC++の出身で、C++とC#のポインターの動作が大きく異なります。
意外にも、このコードはコンパイルできます...そしてさらに...完全に動作します。
class C
{
private readonly int x = 0;
unsafe public void Edit()
{
fixed (int* p = &x)
{
*p = x + 1;
}
Console.WriteLine($"Value: {x}");
}
}
これは私を非常に困惑させます、C++でもconst
オブジェクトを保護するメカニズムがあります(const
C++のreadonly
とほぼ同じですが、const
C#では)、ポインタを介してconst値を任意に変更する十分な理由がないためです。
さらに調べてみると、C++のC++の低レベルのconstポインターに相当するものはなく、次のようになります。
readonly int* p
c#の場合は1つあります。
その場合、pはポイントされたオブジェクトのみを読み取ることができ、それに書き込むことはできません。
const
オブジェクトの場合、C#アドレスを取得する試みを禁止しました。
C++では、const
を変更しようとすると、コンパイルエラーまたは未定義の動作になります。 C#では、これを利用できる可能性があるかどうかわかりません。
注:コメントセクション:C++でのconst
のキャストキャストはこの質問には関係ありません。これは、オブジェクト自体がconst
でない場合にのみ有効で、それ以外の場合はUBだからです。さらに、私は基本的にC#とコンパイル時の動作について話しています。
質問を完全に理解していない場合は、詳細を提供するように依頼できます。私はほとんどの人がこれを正しく理解できないことを発見しました、多分それはそれを明確にしていない私のせいです。
unsafe
キーワードが原因で、この予期しない動作が発生するだけだと言えるでしょう。残念ながら、その読み取り専用フィールドを変更するには、少なくとも2つの方法があります。これらの方法は、安全でなくてもかまいません。これらのメソッドの詳細については、Joe Duffyのブログ投稿 'When is a readonly field not readonly' を参照してください。
読み取り専用でない構造体でフィールドをオーバーラップすることにより:
class C
{
private readonly int x = 0;
class other_C
{
public int x;
}
[StructLayout(LayoutKind.Explicit)]
class Overlap_them
{
[FieldOffset(0)] public C actual;
[FieldOffset(0)] public other_C sneaky;
}
public void Edit()
{
Overlap_them overlapper = new Overlap_them();
overlapper.actual = this;
overlapper.sneaky.x = 1;
Console.WriteLine($"Value: {x}");
}
}
そして、誤ってthis
にrefパラメーターを付けます(これは外部から行われます)。
class C
{
private readonly int x = 0;
public C(int X)
{
x = X;
}
public void Edit(ref C foo)
{
foo = new C(1);
Console.WriteLine($"Value: {x}");
}
}
private static void Main()
{
var c = new C(0);
c.Edit(ref c);
}
3つのメソッドはすべて、完全に明確に定義されたC#であり、ペストのように回避する必要があります。クラスの外部から発生する複雑なエイリアシングの問題があるコードのデバッグを想像してみてください。残念ながら、C#でエイリアシングの問題を解決するための満足のいく解決策はまだありません。