Durante o TechEd Brasil tivemos uma discussão interessante, e fiz um exemplo rápido para demonstrar um conceito. No exemplo eu aparentava chamar um método sobre uma variável nula. Fiz uma aplicação console, que fazia mais ou menos isso:
class Program { public static void Main (string[] args) { Pessoa pessoa; pessoa.Id = 3; Console.WriteLine(pessoa.QualMeuNome()); } }
Ao rodar ela imprimia na console:
Nome3
No entanto, parece haver algo errado. Como foi possível associar o valor 3 à propriedade Id do objeto pessoa, que ao que tudo indica, só pode ser nulo? Ou mais, como podemos chamar um método sobre um objeto nulo?
Pense um pouco na resposta, que já vem abaixo.
.
.
.
.
.
.
.
.
.
.
.
.
Vamos à resposta. Pessoa não é uma classe, é uma estrutura. É um tipo de valor, não de referência, que em geral vive na stack, não na heap (depende de onde foi criado). De qualquer forma, ele sempre possui valor, não pode nunca ser nulo. Da mesma forma que um inteiro sempre existe, e se você não o inicializa ele inicia com o valor padrão, zero, a struct Pessoa inicia no seu valor padrão, que possui o campo público Id com o valor também padrão, zero.
struct Pessoa { public int Id; }
Ok, primeiro problema resolvido, a primeira linha do método Main declara e portanto cria uma pessoa, e a segunda coloca o valor 3 no campo Id desta pessoa. Tudo perfeitamente legal.
E o método?
Essa é mais fácil, é um método de extensão:
static class MetodosPessoa { public static string QualMeuNome(this Pessoa pessoa) { return "Nome" + pessoa.Id; } }
Um método de extensão é um método estático com um toque sintático a mais. Chamamos o método assim:
pessoa.QualMeuNome();
E podemos chamá-lo assim também:
MetodoPessoa.QualMeuNome(pessoa);
O toque sintático que me referi está na declaração do método, é o “this”, logo antes da declaração do parâmetro Pessoa. Parece estranho ter a palavra “this”, usada no corpo de métodos de instância na declaração de um método estático. Essa pequena feature da linguagem permite chamar o método como se ele fosse parte da estrutura Pessoa. No entanto, é bom entender: o resultado na compilação é exatamente o mesmo, que se parece com a chamada estática. Métodos de extensão são o que chamamos de açucar sintático (syntatic sugar). E funcionam com classes também.
Parou por aí? Não, além desta brincadeira trivial há um pouco de teoria que eu gostaria de compartilhar com vocês.
A maioria dos desenvolvedores de .Net entende métodos de extensão como uma maneira de estender tipos, criar código mais elegante; e é para isso que servem mesmo. Mas eles guardam em si uma explicitação útil para o entendimento de como a orientação a objetos normalmente é implementada.
Com métodos de extensão fica mais fácil entender como OO funciona por trás dos panos. Sabem porque? Porque objetos não existem, são meras abstrações criadas pelas linguagens para que possamos pensar mais próximo do problema. Um objeto nada mais é do que uma estrutura de dados, assim como nossa classe Pessoa, e os métodos do objeto nada mais são do que funções soltas que tem como primeiro parâmetro uma estrutura, que é o tal do “objeto”. Adivinhem o nome do parâmetro? Fácil: “this”, é por isso que chamamos os campos como “this.AlgumValor”. Ao chamar o método de instância, o método recebe a estrutura e atua sobre seus campos, consultando e/ou alterando seus valores. Campos privados estão disponíveis somente para estes métodos, que recebem a estrutura como primeiro parâmetro “this”, mas estão indisponíveis para métodos que recebem a estrutura por outro parâmetro que não seja o “this”, ou que a encontram via associação.
No fim das contas, o que temos, é um monte de estruturas de dados e métodos soltos, sendo chamados e passados pra lá e pra cá. Essa arquitetura foi o que permitiu evoluir do C, essencialmente procedural, para o C++, orientado a objetos. É claro que há complexidades, como as trazidas por abstrações como interfaces e herança, ainda mais quando consideramos overrides. Mas no fim das contas, são estruturas e métodos soltos na memória.
No fundo, lá no fundo, OO não existe, é uma mentira, é uma abstração. Mas é uma abstração muito útil!
-//-
Alguém dirá também que estruturas, como estou explicando, não existem, e que tudo são registradores. Outros dirão que tudo é eletricidade. E é verdade. Mas paro por aqui, e fiquem à vontade para continuar descontruindo abstrações!
Giovanni Bassi
Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.