<< C# 4.0 in a Nutshell
ASP.NET MVC 3 Beta e NuPack >>
Mas por que tanta confusão? O fato é que até na documentação da Microsoft diz que Value Types são alocados na Stack, mas é apenas um detalhe de implementação, na runtime distribuída pela Microsoft. Apesar disso não podemos nos basear na implementação para fazer decisões, pois teoricamente numa futura e hipotética versão do .NET pode ser que tudo fique no Heap. Claro que não vai acontecer, mas devemos ter em mente o real significado. Isso não quer dizer que distribuições de outras empresas tenham que funcionar desta forma, dependendo inclusive do SO e do hardware.
Agora por que nem sempre eles ficam na Stack? O motivo é simples, eles só ficam na Stack quando podem. Ficar na Stack tem a vantagem de ser muito mais rápido para desalocar, bastando mover um ponteiro, ao contrário do que muita gente pensa, a alocação no Heap e Stack quase sempre levam o mesmo tempo, não vou entrar em detalhes de como funciona a Stack e Heap, você pode ler mais no meu artigo sobre GC publicado na .NET Magazine.
Um Value Type pode ficar na Stack sempre que for short-lived, isto é, uma variável local que não é usada dentro de um método anônimo ou lambda e desde que o método não seja um iterator, pois nesses casos a variável é "hoisted" e acaba virando uma propriedade de uma classe gerada pelo compilador. Quando a variável é short-lived ela pode ser descartada assim que o método retornar e por isso que Reference Types não podem ficar na Stack, já que podem por exemplo serem atribuídos à uma variável global, o que não acontece com Value Types pois é sempre feito uma cópia deles na atribuição.
Nada disso é motivo pra sair criando Value Types achando que vai melhorar a performance da sua aplicação. Raramente você vai precisar criar um Value Type, e quando precisar é bom seguir algumas boas práticas, como assegurar que seu Value Type é imutável.