Por que não há RAII no .NET?

Sendo principalmente um desenvolvedor C ++ a ausência deRAII (aquisição de recursos é inicialização) em Java e .NET sempre me incomodou. O fato de que o ônus da limpeza é transferido do redator da classe para seu consumidor (por meio detry finally ou .NETusing construir) parece ser marcadamente inferior.

Vejo porque em Java não há suporte para RAII, pois todos os objetos estão localizados no heap e o coletor de lixo inerentemente não suporta a destruição determinística, mas no .NET com a introdução de tipos de valor (struct) temos o candidato (aparentemente) perfeito para RAII. Um tipo de valor criado na pilha tem um escopo bem definido e a semântica do destruidor do C ++ pode ser usada. No entanto, o CLR não permite que um tipo de valor tenha um destruidor.

Minhas buscas aleatórias encontraram um argumento que se um tipo de valor éencaixotado fica sob a jurisdição do coletor de lixo e, portanto, sua destruição se torna não determinista. Eu sinto que este argumento não é forte o suficiente, os benefícios do RAII são grandes o suficiente para dizer que um tipo de valor com um destruidor não pode ser encaixotado (ou usado como um membro da classe).

Para cortar uma longa história curta minha pergunta é: existem outras razões para que os tipos de valor não possam ser usados ​​para introduzir o RAII ao .NET? (ou você acha que meu argumento sobre as vantagens óbvias do RAII é falho?)

Editar: Não devo ter formulado a pergunta com clareza, já que as quatro primeiras respostas não entenderam o ponto. Euconhecer sobreFinalize e suas características não determinísticas, eu sei sobre ousing construir e eu sinto que essas duas opções são inferiores ao RAII.using é mais uma coisa que o consumidor de uma classe deve lembrar (quantas pessoas se esqueceram de colocarStreamReader em umusing quadra?). Minha pergunta é filosófica sobre o design da linguagem, por que é assim e pode ser melhorada?

Por exemplo, com um tipo de valor genérico deterministicamente destrutível, possousing elock palavras-chave redundantes (alcançáveis ​​por classes de bibliotecas):

    public struct Disposer<T> where T : IDisposable
    {
        T val;
        public Disposer(T t) { val = t; }
        public T Value { get { return val; } }
        ~Disposer()  // Currently illegal 
        {
            if (val != default(T))
                val.Dispose();
        }
    }

Não posso deixar de terminar com uma citação que eu vi uma vez, mas atualmente não consigo encontrar sua origem.

Você pode levar minha destruição determinista quando minha mão morta fria sair do escopo. -Anon

questionAnswers(7)

yourAnswerToTheQuestion