Contribuindo para a dúvida sobre a interface IDisposable
Dica:
Segurando a tecla ctrl é e clicando em cima da classe StreamReader ou FileStream, ou clicando em qualquer classe que deseja ver com está implementada, dependendo da IDE, o código fonte é aberto.
No caso do das IDE da JetBrains Rider por exemplo, quando o código aberto referente a tal classe clicada, não existe no seu sistema de arquivos, a IDE baixa o arquivo
.cs
diretamente do repositório oficial.NET
do github e armazena em uma pasta SourcesCache.No caso do Visual Studio Code usando a recente extensão C# Dev Kit, pelo menos até a data de postagem dessa resposta, é possível sim ver uma "implementação" do código fonte até certo nível, por exemplo, é possível ver parcialmente o código de
FileStream.cs
porém não é possível ver a implementação da interfaceStream
que ela implementa. O vscode armazena o arquivo em um diretório como:/tmp/MetadataAsSource/07d2316575214130be41414e7b612a90/DecompilationMetadataAsSourceFileProvider/b3c42c865ba2474eb92ff58b72cc1a84/FileStream.cs
no caso do Linux.
É interessante vasculhar os códigos internos das APIs .NET, sempre dá pra descobrir muita coisa por lá.
Exemplo, no arquivo IDisposable.cs
, existe o seguinte texto:
IDisposable é uma tentativa de ajudar a resolver problemas com finalização determinística. O GC obviamente não deixa nenhuma maneira de saber de forma determinística quando um finalizador será executado. Isso força as classes que mantêm os recursos do sistema operacional ou algum tipo de estado importante (como um FileStream ou uma conexão de rede) a fornecer um método Close ou Dispose para que os usuários possam executar o código de limpeza de forma determinística. Nós formalizamos isso em uma interface com um método. As classes podem implementar IDisposable de forma privada e fornecer um método Close em vez disso, se esse nome for de longe o nome esperado para objetos nesse domínio (ou seja, você não descarta um FileStream, você o fecha).
Essa interface poderia ser teoricamente usada como um marcador por um compilador para garantir que um objeto descartável tenha sido limpo ao longo de todos os caminhos de código se ele tiver sido alocado nesse método, embora na prática qualquer compilador draconiano possa marcar qualquer número de pessoas. Talvez uma ferramenta externa (como Purify ou BoundsChecker) possa fazer isso. Em vez disso, C# adicionou uma cláusula using, que irá gerar uma instrução try/finally onde o recurso passado para a cláusula using sempre terá seu método Dispose chamado. A sintaxe é using(FileStream fs = ...) { .. };
O descarte deve atender às seguintes condições:
1) Ser chamado com segurança várias vezes
2) Libere todos os recursos associados à instância
3) Chame o método Dispose da classe base, se necessário
4) Suprima a finalização desta classe para ajudar o GC reduzindo o número de objetos na fila de finalização.
5) Dispose geralmente não deve lançar exceções, exceto para erros muito sérios que são particularmente inesperados. (ou seja, OutOfMemoryException) Idealmente, nada deve dar errado com seu objeto chamando Dispose.
Se possível, uma classe deve definir um finalizador que chama Dispose. No entanto, em muitas situações, isso é impraticável. Por exemplo, pegue o exemplo clássico de um Stream e um StreamWriter (que tem um buffer interno de dados para gravar no Stream). Se ambos os objetos forem coletados antes de Close ou Dispose terem sido chamados, então o GC pode executar o finalizador para o Stream primeiro, antes do StreamWriter. Nesse ponto, quaisquer dados armazenados em buffer pelo StreamWriter não podem ser gravados no Stream. Nesse caso, não faz muito sentido fornecer um finalizador no StreamWriter, pois você não pode resolver esse problema corretamente.