Ich komme aus C ++ und finde ein ganz anderes Verhalten zwischen Zeigern in C ++ und C #.
Ich finde überraschenderweise, dass dieser Code kompiliert wird ... und sogar ... funktioniert perfekt.
class C
{
private readonly int x = 0;
unsafe public void Edit()
{
fixed (int* p = &x)
{
*p = x + 1;
}
Console.WriteLine($"Value: {x}");
}
}
Das macht mich sehr verwirrt, selbst in C ++ haben wir einen Mechanismus zum Schutz von const
Objekten ( const
in C ++ fast das gleiche wie readonly
in C #, nicht const
in C #), weil wir nicht genug Grund haben, const-Werte willkürlich durch Zeiger zu ändern.
Wenn ich weiter untersuche, finde ich, dass es in C # kein Äquivalent zu C ++ 's konstanten Zeigern auf niedriger Ebene gibt , was ungefähr so aussehen wird:
readonly int* p
in C #, wenn es eine hatte.
Dann kann p nur das Objekt lesen, auf das gezeigt wird, und kann nicht darauf schreiben.
Und für const
Objekte verbot C # die Versuche, ihre Adresse abzurufen.
In C ++ ist jeder Versuch, das zu ändern, const
entweder ein Kompilierungsfehler oder ein undefiniertes Verhalten. In C # weiß ich nicht, ob es eine Möglichkeit gibt, dass wir davon Gebrauch machen können.
Meine Frage lautet also:
- Ist dieses Verhalten wirklich gut definiert? Obwohl ich weiß, dass es in C # kein Konzept wie UB in C ++ gibt
- Wenn ja, wie soll ich es verwenden? Oder nie benutzen?
Hinweis: Im Kommentarbereich: Das Wegwerfen const
in C ++ hat nichts mit dieser Frage zu tun, da es nur gültig ist, wenn das Objekt, auf das verwiesen wird, nicht vorhanden ist const
, andernfalls ist es UB. Außerdem spreche ich im Grunde genommen über C # und das Verhalten beim Kompilieren.
Sie können mich bitten, weitere Details anzugeben, wenn Sie die Frage nicht vollständig verstehen. Ich fand, dass die meisten Leute dies nicht richtig verstehen können, vielleicht ist es meine Schuld, es nicht klar zu machen.
quelle
Antworten:
Ich wünschte, ich könnte sagen, dass Sie dieses unerwartete Verhalten nur aufgrund des
unsafe
Schlüsselworts erhalten. Leider gibt es mindestens zwei weitere Möglichkeiten, um dieses schreibgeschützte Feld zu ändern, die nicht einmal unsicher sind. Weitere Informationen zu diesen Methoden finden Sie in Joe Duffys Blogpost "Wann ist ein schreibgeschütztes Feld nicht schreibgeschützt?" .Durch Überlappen eines Feldes mit einer nicht schreibgeschützten Struktur:
Und durch versehentliches Aliasing
this
mit einem ref-Parameter (dieser erfolgt von außen):Alle drei Methoden sind perfekt definierte C #, die Sie wie die Pest vermeiden sollten. Stellen Sie sich vor, Sie debuggen Code mit komplexen Aliasing-Problemen, die von außerhalb Ihrer Klasse stammen. Leider gibt es immer noch keine zufriedenstellende Lösung, um Aliasing-Probleme in C # zu stoppen.
quelle