Eu venho de C ++ e encontro um comportamento muito diferente entre ponteiros em C ++ e C #.
Surpreendentemente, acho que esse código compila ... E até ... Funciona perfeitamente.
class C
{
private readonly int x = 0;
unsafe public void Edit()
{
fixed (int* p = &x)
{
*p = x + 1;
}
Console.WriteLine($"Value: {x}");
}
}
Isso me deixa muito confuso, mesmo em C ++, temos um mecanismo para proteger const
objetos ( const
em C ++ quase a mesma coisa que readonly
em C #, não const
em C #), porque não temos motivos suficientes para modificar arbitrariamente os valores const através de ponteiros.
Explorando mais, acho que não há equivalente aos ponteiros const de baixo nível do C ++ em C #, que serão algo como:
readonly int* p
em c # se tivesse um.
Então p só pode ler o objeto apontado e não pode gravar nele.
E para const
objetos, o C # proibiu as tentativas de recuperar seu endereço.
No C ++, qualquer tentativa de modificar o const
erro de compilação ou o comportamento indefinido. Em C #, não sei se existe alguma possibilidade de podermos fazer uso disso.
Então, minha pergunta é:
- Esse comportamento é realmente bem definido? Embora eu saiba em C #, não há conceito como UB em C ++
- Se sim, como devo usá-lo? Ou nunca usá-lo?
Nota: Na seção de comentários: jogar fora const
em C ++ não está relacionado a esta pergunta, porque é válido apenas quando o objeto apontado em si não é const
, caso contrário, é UB. Além disso, estou basicamente falando sobre C # e compilar o comportamento do tempo.
Você pode solicitar que eu forneça mais detalhes se não entender completamente a pergunta. Descobri que a maioria das pessoas não consegue entender isso corretamente, talvez seja minha culpa não esclarecer.
fonte
Respostas:
Eu gostaria de poder dizer que você só recebe esse comportamento inesperado por causa da
unsafe
palavra - chave. Infelizmente, existem pelo menos mais duas maneiras de alterar esse campo somente de leitura, que nem exigem segurança. Você pode encontrar mais informações sobre esses métodos no post de Joe Duffy 'When is a readonly field not readonly' .Sobrepondo um campo a uma estrutura não somente leitura:
E acidentalmente alternando
this
com um parâmetro ref (este é feito de fora):Todos os três métodos são C # perfeitamente bem definidos que você deve evitar como uma praga. Imagine o código de depuração com problemas complexos de aliasing decorrentes de fora da sua classe. Infelizmente, ainda não existe uma solução satisfatória para interromper os problemas de alias no C #.
fonte