1. Quais as principais vantagens da plataforma .NET Core em comparação com o .NET Framework?
O .NET Core e o .NET Framework são ambos frameworks para desenvolvimento de aplicações Windows e web. A principal distinção reside na sua arquitetura e alcance. O .NET Core é um framwork de código aberto e multiplataforma, capaz de operar em sistemas Windows, macOS e Linux. Em contraste, o .NET Framework é limitado ao ambiente Windows. As vantagens do .NET Core incluem um footprint mais reduzido, tempos de inicialização mais rápidos, desempenho superior e acesso aos últimos recursos da linguagem C#.
2. Explique o conceito de Injeção de Dependência (DI).
A Injeção de Dependência (DI) é um padrão de design de software que concretiza o Princípio da Inversão de Controle (IoC). O seu objetivo é desacoplar componentes e facilitar a manutenção. Neste paradigma, as dependências de uma classe não são instanciadas internamente, mas sim fornecidas por um agente externo, tipicamente um contêiner IoC. Isto permite que os objetos se concentrem na sua responsabilidade primária. As formas comuns de injeção incluem:
- Injeção por Construtor: As dependências são passadas como parâmetros no construtor da classe.
- Injeção por Propriedade (Setter): As dependências são definidas através de propriedades públicas.
- Injeção por Método: As dependências são passadas como argumentos para um método específico.
3. Quais os ciclos de vida (lifetimes) disponíveis para serviços no contêiner de DI integrado do ASP.NET Core?
O contêiner de injeção de dependência integrado do ASP.NET Core suporta três ciclos de vida para serviços:
- Transient: Uma nova instância é criada sempre que é solicitada do contêiner. Adequado para serviços sem estado e leves.
- Scoped: Uma única instância é criada por escopo de solicitação client. É partilhada dentro do mesmo escopo (ex: uma única requisição HTTP).
- Singleton: Uma única instância é criada e partilhada por toda a aplicação durante o seu tempo de vida.
4. Qual a função dos componentes de middleware no ASP.NET Core e como são configurados?
Os middlewares são componentes fundamentais no pipeline de processamento de requisições e respostas HTTP do ASP.NET Core. Eles podem inspecionar, modificar, delegar ou terminar o fluxo da requisição. A ordem de configuração no pipeline é crucial, pois define a sequência de execução. Middlewares comuns fornecem funcionalidades como roteamento, autenticação, autorização, tratamento de exceções, log e compressão de resposta.
5. Comente sobre o uso de ORM no .NET, mencionando Entity Framework e SqlSugar.
O Entity Framwork (EF) Core é o ORM (Object-Relational Mapper) padrão e amplamente adotado no ecossistema .NET, oferecendo integração profunda com o ASP.NET Core e suporte a Code-First e Database-First. O SqlSugar é um ORM alternativo, também maduro e com foco em performance e funcionalidades avançadas. Suas características distintivas incluem suporte nativo a sharding (particionamento de tabelas), operações em lote otimizadas para grandes volumes de dados, e um conjunto rico de recursos para arquiteturas multitenancy.
6. Em que cenários a Reflexão (Reflection) é tipicamente aplicada no .NET?
A reflexão permite a inspeção e manipulação de metadados de tipos (classes, métodos, propriedades) em tempo de execução. Os seus usos comuns incluem:
- Arquiteturas Extensíveis e Plugins: Carregamento dinâmico e instanciação de tipos de assemblies externos.
- Mapeamento e Serialização: Leitura de atributos para mapeamento de objetos para DTOs ou formatos de dados.
- Criação de Proxies e AOP: Geração dinâmica de código para aspectos transversais como logging.
- Frameworks e Bibliotecas: Muitos frameworks de DI, ORM e teste usam reflexão internamente.
7. Descreva o papel do Garbage Collector (GC) na gestão de memória do .NET.
O Garbage Collector (GC) é um sistema automático de gestão de memória no runtime do .NET. Ele identifica e recupera objetos na memória (heap) que não são mais referenciados por nenhuma parte do código ativo, liberando essa memória para reutilização. Este mecanismo elimina a necessidade de gestão manual de memória, reduzindo drasticamente erros comuns como vazamentos de memória (memory leaks) e acesso a memória já liberada (dangling pointers).
8. O que é o framework ABP e como ele se relaciona com os princípios do DDD?
O ABP (ASP.NET Boilerplate) é um framework de aplicação abrangente para .NET que fornece uma infraestrutura modulável para construir aplicações corporativas de alta qualidade. Ele adota e promove a aplicação do Domain-Driven Design (DDD). O DDD é uma abordagem de design de software focada na criação de um modelo rico do domínio do negócio. Conceitos centrais incluem:
- Entidades e Objetos de Valor: Objetos com identidade única versus objetos definidos por seus atributos.
- Agregados e Raiz do Agregado: Agrupamentos de objetos tratados como uma unidade de consistência transacional.
- Serviços de Domínio: Lógica de negócio que não pertence naturalmente a uma entidade.
- Eventos de Domínio: Mecanismo para comunicação entre agregados de forma desacoplada.
9. Estratégias comuns para otimização de performance em aplicações .NET.
A otimização de performance é multifacetada. Estratégias comuns incluem:
- Nível de Aplicação: Uso de coleções e algoritmos eficientes, minimização de alocações, uso de
Span<t>eMemory<t>, implementação de processamento assíncrono/paralelo. - Nível de Acesso a Dados: Uso de índices em banco de dados, otimização de consultas LINQ, uso de operações em lote, e implementação de caches (como Redis ou caches em memória).
- Nível de Infraestrutura/Web: Ativação de compressão de resposta (Brotli, Gzip), implementação de paginação, uso de CDN, e configuração de servidores web (Kestrel, IIS) e proxies reversos (Nginx).
10. Explique o papel do cache e as políticas de invalidação.
O cache é uma técnica que armazena dados em um local de acesso rápido (geralmente memória) para atender requisições futuras mais rapidamente, reduzindo a carga em recursos mais lentos como bancos de dados ou APIs. A implementação eficaz requer uma política de invalidação clara para manter a consistência dos dados. Políticas comuns incluem tempo de vida absoluto (TTL), invalidação baseada em eventos (ex: quando os dados-fonte são alterados), e invalidação por dependência.
11. Mencione frameworks front-end e sua integração com backends .NET.
Frameworks como React, Angular e Vue.js são frequentemente utilizados para construir aplicações de página única (SPA) que consomem APIs construídas com ASP.NET Core Web API. A comunicação tipicamente ocorre via HTTP/HTTPS usando JSON. Conceitos como propriedades reativas e gestão de estado (ex: Vuex no Vue, Redux no React) são centrais nestes frameworks.
12. Descreva o padrão MVVM.
MVVM (Model-View-ViewModel) é um padrão arquitetural popular em aplicações com interfaces de usuário ricas, como as desenvolvidas com WPF, Xamarin ou frameworks SPA. Ele separa a lógica da aplicação em três componentes:
- Model: Representa os dados e a lógica de negócio.
- View: A interface visual que exibe os dados e captura a interação do usuário.
- ViewModel: Um intermediário que expõe dados e comandos da Model para a View, muitas vezes utilizando Data Binding para sincronização automática.
13. Diferencie os delegados Func e Action em C#.
Tanto Func quanto Action são tipos de delegados genéricos. A diferença fundamental é que Func encapsula um método que retorna um valor, enquanto Action encapsula um método que não retorna valor (equivalente a void). Por exemplo:
Func<int, string> converterParaString = numero => numero.ToString(); // Retorna uma string.
Action<string> imprimir = mensagem => Console.WriteLine(mensagem); // Não retorna nada.
14. Explique o conceito de Delegates e Events em C#.
Um delegate é um tipo que define uma referência a um método com uma assinatura específica, funcionando como um ponteiro de função segura. Um event é uma estrutura de alto nível construída sobre delegates, que implementa o padrão Observador (pub/sub). Events restringem o acesso, permitindo que apenas a classe que os declara (publisher) possa invocá-los, enquanto qualquer outra classe (subscriber) pode se inscrever neles. Action e Func são delegates genéricos predefinidos.
15. Compare Classes, Interfaces e os modificadores abstract e virtual.
- Classe vs Interface: Uma classe pode conter implementação, estado (campos) e construtores. Uma interface define apenas um contrato (métodos, propriedades, eventos) sem implementação (embora interfaces C# 8+ possam ter implementações padrão).
abstractvsvirtual: Um método ou classeabstractnão possui implementação e força as classes derivadas a implementá-lo. Um métodovirtualtem uma implementação padrão, mas pode ser sobrescrito (override) por classes derivadas.
16. Diferencie string e StringBuilder.
Em C#, uma instância de string é imutável. Qualquer operação que pareça modificar uma string (como concatenação) na verdade cria um novo objeto na memória. O StringBuilder é uma classe mutável projetada para cenários onde múltiplas modificações em uma sequência de caracteres são necessárias, como dentro de um loop. Ele otimiza a manipulação interna do buffer, resultando em performance significativamente melhor em operações intensivas de concatenação.
17. Descreva os passos para comunicação síncrona via Socket.
Uma comunicação TCP síncrona básica envolve:
- Servidor: Criar um
Socket, associá-lo a um endereço e porta (Bind), colocá-lo em modo de escuta (Listen), aceitar uma conexão (Accept), trocar dados (Send/Receive), e finalmente fechar a conexão. - Cliente: Criar um
Socket, conectar-se ao endereço do servidor (Connect), trocar dados (Send/Receive), e fechar a conexão.
18. Diferencie as requisições HTTP GET e POST.
- GET: Solicita dados de um recurso específico. Parâmetros são enviados na URL (query string). É idempotente (repetir a requisição produz o mesmo resultado) e considerado seguro apenas para leitura.
- POST: Envia dados para serem processados por um recurso. Os dados são enviados no corpo da requisição, permitindo volumes maiores e tipos de dados diversos. Não é idempotente.
19. Por que a Reflexão em C# pode ser considerada lenta?
O desempenho inferior da reflexão decorre de várias características inerentes ao seu funcionamento em tempo de execução: a necessidade de inspecionar e validar metadados dinamicamente, a impossibilidade de otimizações estáticas como inlining pelo compilador JIT, operações frequentes de boxing/unboxing ao lidar com tipos de valor, e a sobrecarga de segurança na verificação de permissões de acesso.
20. Quais são os tipos de coleção fundamentais no .NET?
O .NET oferece uma vasta gama de tipos de coleção através da System.Collections.Generic namespace. Os mais comuns incluem:
- List<T>: Lista dinâmica e indexada.
- Dictionary<TKey, TValue>: Coleção de pares chave-valor para busca rápida.
- HashSet<T>: Coleção de elementos únicos, otimizada para testes de pertinência.
- Queue<T>: Estrutura FIFO (Primeiro a Entrar, Primeiro a Sair).
- Stack<T>: Estrutura LIFO (Último a Entrar, Primeiro a Sair).
- LinkedList<T>: Lista duplamente encadeada.
21. Como realizar upload de múltiplos arquivos e dados JSON simultaneamente em uma ASP.NET Core Web API?
Uma abordagem comum é utilizar o binding de modelo com um DTO (Data Transfer Object) que contenha tanto uma propriedade para os arquivos (do tipo IFormFile ou List<IFormFile>) quanto propriedades para os dados serializados do corpo JSON. A requisição HTTP pode ser do tipo multipart/form-data, com os arquivos e os dados JSON (como uma string) enviados em partes separadas.
22. Quais são os padrões de programação assíncrona disponíveis no .NET?
O .NET suporta múltiplos padrões, dos quais os mais modernos e recomendados são:
- TAP (Task-based Asynchronous Pattern): Utiliza as palavras-chave
asynceawaite os tiposTaskeTask<T>. É o padrão preferido. - APM (Asynchronous Programming Model): Padrão mais antigo, baseado em métodos
BegineEnde na interfaceIAsyncResult. - EAP (Event-based Asynchronous Pattern): Padrão baseado em eventos, comum em APIs mais antigas do Windows Forms.
23. Explique a diferença entre processos e threads.
Um processo é uma instância de um programa em execução. Ele fornece um ambiente isolado com seu próprio espaço de memória virtual. Múltiplos threads podem existir dentro de um único processo. Os threads de um processo partilham o mesmo espaço de endereçamento, código e recursos, mas cada um possui sua própria pilha de execução. A criação de múltiplos threads (multithreeading) permite a execução concorrente de tarefas dentro de uma mesma aplicação.
24. Qual a relação entre a instrução using e a interface IDisposable?
A instrução using em C# é um conveniência sintática que garante a chamada do método Dispose() de um objeto que implementa a interface IDisposable, mesmo que ocorra uma exceção. Ela é equivalente a um bloco try-finally. IDisposable define um padrão para a liberação explícita de recursos não gerenciados, como handles de arquivo, conexões de banco de dados ou sockets.
25. Diferencie threads de primeiro plano (foreground) e de segundo plano (background).
A principal diferença está no seu impacto no ciclo de vida da aplicação:
- Foreground Thread: Mantém o processo da aplicação vivo. O processo só encerra quando todos os seus threads foreground terminam.
- Background Thread: Não impede o encerramento do processo. Quando todos os threads foreground terminam, o runtime encerra automaticamente todos os threads background.
26. Explique o operador await e sua diferença em relação a Task.Result.
O operador await é usado dentro de um método marcado com async. Ele suspende a execução do método atual até que a tarefa assíncrona aguardada seja concluída, sem bloquear o thread. Isso permite que o thread seja reutilizado para outras operações. Em contraste, acessar a propriedade Task.Result (ou chamar Task.Wait()) em uma tarefa não concluída bloqueia o thread chamador até que a tarefa termine, o que pode levar a deadlocks em aplicações com um único thread de sincronização, como interfaces de usuário.
27. Quais os tipos de locks comuns no .NET e qual a natureza do lock statement?
Além do lock statement, mecanismos de sincronização comuns incluem SemaphoreSlim (para limitar acesso concorrente), ManualResetEventSlim e AutoResetEvent (para sinalização), Monitor (a base do lock), e ReaderWriterLockSlim (para permitir múltiplas leituras ou uma escrita exclusiva). O lock statement em C# é um atalho para o uso da classe Monitor, que é um lock exclusivo baseado em mutação (mutual exclusion lock).
28. Quais as restrições para o objeto de lock (parâmetro do lock)?
O objeto utilizado como argumento do lock deve ser uma referência type (reference type). Se um valor type (value type) for passado, ele será "boxed" (empacotado) para um novo objeto a cada chamada, o que anula completamente o propósito do lock, pois cada thread estaria bloqueando em um objeto diferente. O objeto deve ser privado e estático para sincronizar threads estáticos, ou de instância para sincronizar threads da mesma instância.
29. Demonstre como realizar um LEFT JOIN usando LINQ.
O operador join em LINQ com a cláusula into e o operador DefaultIfEmpty() simula um left join. A sintaxe é mais clara na sintaxe de método (fluent). Exemplo conceitual:
var resultado = from a in listaA
join b in listaB on a.Id equals b.AId into grupoB
from bMatch in grupoB.DefaultIfEmpty()
select new { A = a, B = bMatch };