Considere esta aula:
public class Number
{
[System.Obsolete()] public string ToExactString() => "";
[System.Obsolete()] public override string ToString() => "";
}
Agora, considere este código:
Number number = new();
string s1 = number.ToExactString();
string s2 = number.ToString();
E agora, observe o que acontece:
- A invocação de
ToExactString()
é renderizada pelo Visual Studio com um tachado, e o compilador gera o aviso CS0612: "'member' está obsoleto". - A invocação de também
ToString()
é renderizada pelo Visual Studio com um tachado, mas o compilador não gera nenhum aviso.
Como resultado:
Não importa se meus olhos envelhecidos notam o tachado na invocação de ToExactString()
, porque o compilador me avisará durante a compilação, e eu posso até mesmo habilitar "tratar todos os avisos como erros" para garantir, então nunca executarei acidentalmente um código invocando um método obsoleto.
Entretanto, se eu não notar o tachado na invocação disso ToString()
, nunca saberei.
Observe o seguinte:
A diferença entre os dois métodos é que ToExactString()
não é uma substituição, enquanto ToString()
é uma substituição de um método não obsoleto, mas isso deveria ser completamente irrelevante e completamente inconsequente neste cenário, porque estou mantendo uma referência a Number
, não uma referência a object
.
Não que isso importe, mas para deixar claro, em todos os meus projetos C# eu tenho CS0809: "Obsolete member overrides non-obsolete member" desabilitado , já que esse aviso é completamente inútil, já que é perfeitamente aceitável e até altamente desejável em alguns casos ter um membro obsoleto que substitua um membro não obsoleto, como o caso aqui com ToString()
. O ponto aqui é que eu quero criar uma substituição obsoleta, que ninguém deve invocar diretamente, mesmo que ela possa ser legitimamente invocada por código que mantenha uma referência à classe base.
O Visual Studio renderiza todas as invocações com um tachado, o que mostra que o Visual Studio entende perfeitamente qual método está sendo invocado em cada caso, enquanto Roslyn finge não entender qual método é invocado no caso de ToString()
, como se o fato de ser uma substituição importasse de alguma forma.
Se [System.Obsolete()]
for substituído por [System.Obsolete("message")]
então o aviso na invocação de ToExactString()
alterações em CS0618: 'membro' está obsoleto: 'mensagem', mas absolutamente nada mais muda.
As perguntas:
- Isso é um bug no compilador C#?
- Existe alguma solução ou solução alternativa conhecida?