Pergunta

Eu estou tentando ter certeza de que a minha compreensão da IDisposable está correto e não é algo que eu ainda não estou muito certo sobre.

IDisposable parece servir dois fins.

  1. Para fornecer uma convenção para "shut down" um objeto gerenciado sob demanda.
  2. Para fornecer uma convenção para livre "recursos não gerenciados", realizada por um objeto gerenciado.

A minha confusão vem de identificar quais cenários têm "recursos não gerenciados" no jogo.

Say você estiver usando um Microsoft-fornecido pelo IDisposable execução (gerenciado) classe (por exemplo, banco de dados ou relacionados socket-).

  1. Como você sabe se está implementando IDisposable por apenas 1 ou 1 & 2 acima?
  2. Você é responsável por certificar-se de que os recursos não gerenciados que pode ou não pode exercer internamente são liberados? Caso você seja adicionando um finalizador (isso seria o mecanismo certo?) Para sua própria classe que chama instanceOfMsSuppliedClass.Dispose ()?
Foi útil?

Solução

  1. Como você sabe se está a implementar IDisposable para apenas 1 ou 1 & 2 acima?

A resposta à sua primeira pergunta é "você não precisa saber". Se você estiver usando código de terceiros, então você é a sua misericórdia para algum momento - você tem que confiar que ele é descartar-se corretamente quando você chamar Dispose sobre ele. Se não tiver certeza ou você acha que há um erro, você poderia sempre tentar usar refletor () para desmontá-lo (se possível) e confira o que está fazendo.

  1. Am I responsável por garantir que os recursos não gerenciados que podem ou Não segure internamente são liberados? Devemos Eu estar adicionando um finalizador (teria que ser o mecanismo certo?) para minha própria classe que as chamadas instanceOfMsSuppliedClass.Dispose ()?

Você deve raramente, ou nunca, necessidade de implementar um finalizador para suas aulas se você estiver usando Net 2.0 ou superior. Finalizadores adicionar sobrecarga para sua classe, e, geralmente, não oferecem mais funcionalidade então você precisa com apenas implementar Dispose. Eu recomendo visitar este artigo para uma boa visão geral sobre o descarte corretamente. No seu caso, você gostaria de chamar instanceofMSSuppliedClass.Dispose() em seu próprio método Dispose ().

Em última análise, chamando Dispose () em um objeto é uma boa prática, porque explicitamente permite que o know GC que você é feito com o recurso e permite ao usuário a capacidade de limpá-lo imediatamente e, indiretamente, documenta o código, permitindo que outros programadores sabem que o objeto é feito com os recursos nesse ponto. Mas mesmo se você esquecer de chamá-lo explicitamente, isso vai acontecer, eventualmente, quando o objeto é não enraizadas (Net é uma plataforma gerenciada depois de tudo). Finalizadores só deve ser implementado se o objeto tem recursos não gerenciados que precisam de limpeza implícita (ou seja, há uma chance do consumidor pode se esqueça de limpá-lo, e que isso vai ser problemático).

Outras dicas

Você deve sempre chamar Dispose em objetos que implementam IDisposable (a menos que especificamente dizer' é uma convenção útil, como da ASP.NET MVC HtmlHelper.BeginForm). Você pode usar a instrução "usando" para fazer isso fácil. Se você pendurar em uma referência de um IDisposable em sua classe como um campo de membro, então você deve implementar IDisposable usando o descartável padrão para limpar esses membros. Se você executar uma ferramenta de análise estática como FxCop ele vai dizer o mesmo.

Você não deve estar tentando adivinhar a interface. Hoje essa classe não pode usar um recurso não gerenciado, mas o que acontece com a próxima versão?

Você não é responsável pelo conteúdo de um objeto. Dispose () deve ser transparente, e libertar o que ele precisa para libertar. Depois disso, você não é responsável por isso.

recursos não gerenciados são recursos como você criaria em (gerenciado) C ++, onde alocar a memória através de ponteiros e declarações "novos", em vez de declarações "gcnew". Quando você está criando uma classe em C ++, você é responsável por apagar essa memória, uma vez que é a memória nativa, ou não gerenciado, eo coletor de lixo não sobre isso. Você também pode criar essa memória não gerenciado através de alocações do marechal, e, i iria assumir, código inseguro.

Ao usar Managed C ++, você não tem que implementar manualmente a classe IDisposable também. Quando você escreve o seu deconstructor, será compilado para uma função Dispose ().

Se a classe em questão é fornecido pela Microsoft (ie .. banco de dados, etc ..), então a manipulação de Descarte (de IDisposable) provavelmente já ser cuidado, é só até você para chamá-lo. Por exemplo, a prática padrão, utilizando um banco de dados seria parecido com:

//...
using (IDataReader dataRead = new DataReaderObject())
{
   //Call database
}

Este é essencialmente o mesmo que escrever:

IDataReader dataRead = null;
try
{
    dataRead = new DataReaderObject()
    //Call database
}
finally
{
    if(dataRead != null)
    {
        dataRead.Dispose();
    }
}

Pelo que eu entendo, é geralmente uma boa prática para você usar o antigo em objetos que herdam IDisposable uma vez que irá garantir liberação adequada dos recursos.

Quanto a usar IDisposable mesmo, a implementação é até você. Depois de herdar-lo você deve garantir que o método contém o código necessário para dispor de todas as conexões de banco de dados que você pode ter criado manualmente, libertando de recursos que podem permanecer ou prevenir o objeto de ser destruído, ou apenas limpar grandes pools de recursos (como imagens ). Isto também inclui recursos não gerenciados, por exemplo, código marcado dentro de um bloco "inseguro" é um código essencialmente não gerenciado que pode permitir a manipulação de memória direta, algo que definitivamente precisa de limpeza.

O termo "recurso não gerenciado" é algo de um equívoco. O conceito essencial é a de uma ação emparelhado - executando uma ação cria uma necessidade para executar alguma ação de limpeza. Abrir um arquivo cria uma necessidade para a fechar. Discar um modem cria uma necessidade para desligar. Um sistema pode sobreviver a uma falha para executar uma operação de limpeza, mas as consequências podem ser graves.

Quando um objeto é dito que "recursos não gerenciados Hold", o que realmente significa é que o objeto tem a informação e impulso necessário para executar alguma operação de limpeza exigido em alguns outros entidade, e não há é especial razão para acreditar que as informações e ímpeto existe em qualquer outro lugar. Se o único objeto com tais informações e ímpeto é completamente abandonada, a operação de limpeza necessária nunca ocorrerá. O objetivo do .Dispose é forçar um objeto para realizar qualquer limpeza necessária, de modo que ele pode ser abandonado com segurança.

Para fornecer alguma proteção contra códigos que abandonos objetos sem primeiro chamado Dispose, o sistema permite que as classes se inscrever para "finalização". Se um objeto de uma classe registrada é abandonado, o sistema dará o objeto a chance de realizar operação de limpeza em outras entidades antes de ser abandonada para sempre. Não há nenhuma garantia quanto à rapidez com que o sistema vai notar que um objeto foi abandonada, no entanto, e várias circunstâncias podem impedir que um objeto do que está sendo oferecido a sua chance de limpar. O termo "recurso gerenciado" é por vezes utilizado para se referir a um objeto que terá que realizar uma limpeza antes de ser abandonada, mas que irá registrar automaticamente e tentar realizar essa limpeza se alguém deixa de chamar Dispose.

Por que isso importa para você?

Quando possível, eu embrulhar o escopo de um objeto descartável numa usando. Isto exige descarte no final do usando. Quando não me chamar explicitamente dispor sempre que eu já não precisa do objeto.

Se por motivo de 1 ou razão 2 não é necessário.

Sim, você é responsável para chamar o método Dispose - ou melhor declaração utilização using. Se um objeto está implementando IDisposable, você deve sempre eliminá-lo, não importa o quê.

using (var myObj = new Whatever())
{
   // ..
}

é semelhante ao

{
  var myObj;
  try
  {
     myObj = new Whatever();
     // ..
  } 
  finally
  {
    if (myObj != null)
    {
      ((IDisposable)myObj).Dispose();
    }
  }
} // object scope ends here

Editar : tentativa Adicionado / finalmente, graças a Talljoe - Uau, isso é complicado para obtê-lo direito:)

EDIT2: Não estou dizendo que você deve usar a segunda variante. Eu só queria mostrar que "usando" é agradável açúcar sintático para um monte de código que pode ficar bastante confuso e difícil de acertar.

Uma peça que está faltando aqui é o finalizador - meu hábito tem sido se eu implementar IDisposable Eu também tenho um finalizador para chamar Dispose () apenas no caso o meu cliente não. Sim, ele adiciona sobrecarga mas se Dispose () é chamado do que os elimina GC.SuppressFinalize (this) chamá-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top