1
resposta

Contribuindo um pouco mais

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 interface Stream 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.
1 resposta

Olá Andrey, tudo bem?

Obrigada por compartilhar essa dica valiosa sobre como visualizar o código fonte das classes no .NET. Realmente é muito interessante vasculhar os códigos internos das APIs para descobrir mais sobre o funcionamento das classes e interfaces.

A interface IDisposable é muito importante para garantir a correta liberação de recursos em uma aplicação. Como mencionado no texto que você compartilhou, a interface IDisposable é uma tentativa de ajudar a resolver problemas com finalização determinística, ou seja, garantir que os recursos sejam liberados de forma previsível e determinística.

Ao implementar a interface IDisposable em uma classe, você deve fornecer um método Dispose que libera todos os recursos associados à instância e chama o método Dispose da classe base, se necessário. É importante também suprimir a finalização da classe para ajudar o GC a reduzir o número de objetos na fila de finalização.

Além disso, é recomendado que uma classe defina um finalizador que chama o método Dispose, para garantir que os recursos sejam liberados mesmo se o método Dispose não for chamado explicitamente. No entanto, em muitas situações, isso pode ser impraticável, como no exemplo mencionado no texto do Stream e do StreamWriter.

Espero ter ajudado e bons estudos!