flashcards_csharp_senior

(114 cards)

1
Q

Qual a diferença entre tipos de valor (value types) e tipos de referência (reference types) em C#?

A

Tipos de valor (int, double, struct, enum, bool) são armazenados na stack e contêm o dado diretamente. Tipos de referência (class, string, array, delegate) são armazenados na heap e a variável contém apenas um ponteiro/referência para o objeto. Ao copiar um value type, cria-se uma cópia independente; ao copiar um reference type, ambas as variáveis apontam para o mesmo objeto.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

O que é boxing e unboxing em C#?

A

Boxing é o processo de converter um value type em object (reference type), alocando memória na heap. Unboxing é o inverso: extrair o value type de dentro do object. Boxing/unboxing tem custo de performance e deve ser evitado em loops ou código de alto desempenho. Exemplo: int x = 42; object o = x; (boxing) int y = (int)o; (unboxing).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Para que serve o modificador ‘ref’ em parâmetros de método?

A

O modificador ‘ref’ permite passar um argumento por referência, ou seja, o método recebe uma referência direta à variável original, podendo modificá-la. A variável deve ser inicializada antes de ser passada. Diferente de ‘out’, que não exige inicialização prévia mas obriga o método a atribuir um valor.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Qual a diferença entre ‘ref’, ‘out’ e ‘in’ em parâmetros?

A

‘ref’: passa por referência, variável deve ser inicializada antes, pode ser lida e modificada. ‘out’: passa por referência, não precisa ser inicializada, método DEVE atribuir valor antes de retornar. ‘in’: passa por referência somente leitura, o método não pode modificar o valor. ‘in’ é útil para structs grandes para evitar cópia sem permitir modificação.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

O que são records em C#? Quando usá-los?

A

Records são tipos de referência (record class) ou valor (record struct) imutáveis por padrão, introduzidos no C# 9. Possuem igualdade por valor (não por referência), sintaxe concisa com positional parameters, método ToString() automático e suporte a ‘with’ expressions para criar cópias modificadas. Ideais para DTOs, eventos de domínio e objetos de valor (Value Objects).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Explique o conceito de string interpolation em C#.

A

String interpolation permite embutir expressões diretamente em strings usando o prefixo $ e chaves {}. Exemplo: $”Olá, {nome}! Você tem {idade} anos.”. É mais legível que string.Format() ou concatenação. Pode-se aplicar formatação: $”{valor:C2}” para moeda, $”{data:dd/MM/yyyy}” para datas.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Qual a diferença entre ‘switch statement’ tradicional e ‘switch expression’ em C#?

A

O switch statement (clássico) usa case/break e executa blocos de código. O switch expression (C# 8+) é uma expressão que retorna um valor, usa ‘=>’ e é mais conciso. Switch expressions suportam pattern matching avançado: type patterns, property patterns, tuple patterns e relational patterns.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

O que são arrays multidimensionais vs jagged arrays em C#?

A

Arrays multidimensionais (int[,]) têm dimensões fixas e formam uma matriz retangular. Jagged arrays (int[][]) são arrays de arrays, onde cada sub-array pode ter tamanho diferente. Jagged arrays geralmente têm melhor performance porque o CLR otimiza arrays unidimensionais. Use multidimensionais para matrizes regulares e jagged para estruturas irregulares.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Explique a diferença entre List<T> e Array em C#.</T>

A

Arrays têm tamanho fixo definido na criação, acesso O(1) por índice. List<T> é uma coleção dinâmica que internamente usa um array que é redimensionado automaticamente (duplicando a capacidade). List<T> oferece métodos como Add, Remove, Contains, Sort. Use arrays quando o tamanho é conhecido e fixo; List<T> quando precisa de tamanho dinâmico.</T></T></T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

O que é um construtor em C#? Quais tipos existem?

A

Construtor é um método especial chamado ao criar uma instância. Tipos: (1) Construtor padrão (sem parâmetros), (2) Construtor parametrizado, (3) Construtor estático (static, executado uma vez antes do primeiro uso da classe), (4) Construtor privado (impede instanciação externa, usado em Singleton). Constructor chaining permite um construtor chamar outro com ‘this()’.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Qual a diferença entre propriedades (properties) e campos (fields)?

A

Campos são variáveis declaradas diretamente na classe. Propriedades encapsulam campos com get/set accessors, permitindo validação, lógica computada e controle de acesso. Propriedades podem ser auto-implementadas (get; set;), somente leitura (get;), com init-only setter (init;), ou computadas (sem backing field). Prefira propriedades para membros públicos.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

O que são propriedades computadas (computed properties)?

A

Propriedades computadas não possuem backing field; seu valor é calculado dinamicamente a partir de outros membros. Exemplo: public decimal Total => Preco * Quantidade; São somente leitura e recalculadas a cada acesso. Úteis para valores derivados que devem estar sempre sincronizados com os dados originais.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Qual a diferença entre classes estáticas e métodos estáticos?

A

Classes estáticas não podem ser instanciadas e só podem conter membros estáticos. São seladas (sealed) implicitamente. Métodos estáticos pertencem à classe, não a uma instância, e não acessam membros de instância. Use classes estáticas para utilitários e helpers. Métodos estáticos são úteis para operações que não dependem do estado do objeto.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Explique herança em C#. Qual a diferença entre ‘virtual’ e ‘abstract’?

A

Herança permite que uma classe derivada herde membros de uma classe base. ‘virtual’ marca um método que TEM implementação padrão mas PODE ser sobrescrito com ‘override’. ‘abstract’ marca um método que NÃO TEM implementação e DEVE ser sobrescrito nas classes derivadas. Classes com membros abstract devem ser declaradas como abstract e não podem ser instanciadas.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

O que é polimorfismo? Dê exemplos.

A

Polimorfismo permite tratar objetos de diferentes tipos de forma uniforme. Em C#: (1) Polimorfismo de subtipo: uma variável do tipo base pode referenciar objetos derivados (Animal a = new Dog()). (2) Polimorfismo paramétrico: Generics (List<T>). (3) Polimorfismo ad-hoc: sobrecarga de métodos (overloading). O método chamado é resolvido em runtime (virtual dispatch) ou compile-time (overloading).</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Qual a diferença entre interfaces e classes abstratas em C#?

A

Interfaces: contrato puro (antes do C# 8), suportam herança múltipla, não têm estado (campos), desde C# 8 podem ter implementação padrão. Classes abstratas: podem ter estado (campos), construtores, membros com implementação, mas só suportam herança simples. Use interfaces para definir capacidades (IDisposable, IEnumerable); classes abstratas para compartilhar código entre classes relacionadas.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

O que são Extension Methods? Quando usá-los?

A

Extension Methods permitem adicionar métodos a tipos existentes sem modificá-los ou criar subclasses. São métodos estáticos em classes estáticas, com o primeiro parâmetro precedido por ‘this’. Exemplo: public static bool IsNullOrEmpty(this string s). Usados extensivamente em LINQ. Úteis para adicionar funcionalidade a tipos que você não controla.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Explique o operador ‘is’ e pattern matching em C#.

A

O operador ‘is’ verifica se um objeto é de um determinado tipo. Com pattern matching (C# 7+): ‘is Type variavel’ faz verificação e cast simultaneamente. C# 8+ adicionou: property patterns (obj is { Prop: value }), tuple patterns, positional patterns. C# 9+: relational patterns (is > 0 and < 100), logical patterns (is not null).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

O que são delegates em C#?

A

Delegates são tipos que representam referências a métodos com assinatura específica. São type-safe function pointers. Delegates built-in: Action (sem retorno), Func<T,TResult> (com retorno), Predicate<T> (retorna bool). Delegates são a base para eventos e são usados extensivamente com LINQ e programação funcional em C#.</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Como funcionam eventos em C#?

A

Eventos são baseados em delegates e implementam o padrão Observer. Declarados com ‘event’ keyword, restringem operações externas a += (subscribe) e -= (unsubscribe), impedindo invocação direta ou reatribuição fora da classe. O publisher dispara o evento; subscribers registram handlers. Padrão: public event EventHandler<TEventArgs> NomeEvento.</TEventArgs>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Explique try-catch-finally em C#.

A

try: bloco de código que pode lançar exceções. catch: captura e trata exceções específicas (pode ter múltiplos catches, do mais específico ao mais genérico). finally: sempre executa, independente de exceção (usado para liberar recursos). ‘using’ statement é syntactic sugar para try-finally com IDisposable. Sempre capture exceções específicas, nunca apenas Exception genérico em produção.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Quando criar exceções customizadas? Como implementar?

A

Crie exceções customizadas quando erros de domínio precisam de contexto adicional que exceções padrão não fornecem. Herde de Exception (ou ApplicationException). Implemente pelo menos 3 construtores: sem parâmetros, com mensagem, e com mensagem + inner exception. Adicione propriedades para dados de contexto. Exemplo: InvalidTransactionException com TransactionId.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

O que é rethrowing de exceções? Qual a diferença entre ‘throw’ e ‘throw ex’?

A

‘throw;’ (sem argumento) relança a exceção preservando o stack trace original. ‘throw ex;’ relança mas RESETA o stack trace, perdendo informação de onde o erro originou. Sempre use ‘throw;’ para rethrow. Use ‘throw new Exception(msg, ex)’ para wrapping, passando a exceção original como InnerException.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Explique os principais métodos LINQ: Where, Select, OrderBy, GroupBy.

A

Where: filtra elementos por condição (como SQL WHERE). Select: projeta/transforma cada elemento (como SQL SELECT). OrderBy/OrderByDescending: ordena elementos. GroupBy: agrupa elementos por chave, retornando IGrouping<TKey, TElement>. Todos usam deferred execution (executam apenas quando o resultado é iterado). São extension methods em IEnumerable<T>.</T>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
O que é deferred execution (execução adiada) em LINQ?
Deferred execution significa que a query LINQ não é executada quando definida, mas sim quando o resultado é enumerado (foreach, ToList, ToArray, Count, etc.). Isso permite compor queries incrementalmente e evitar processamento desnecessário. Operadores que forçam execução imediata: ToList(), ToArray(), Count(), First(), Any(). Cuidado com múltiplas enumerações do mesmo IEnumerable.
26
Qual a diferença entre Any(), All() e Contains() em LINQ?
Any(): retorna true se QUALQUER elemento satisfaz a condição (ou se a coleção não está vazia, sem argumento). All(): retorna true se TODOS os elementos satisfazem a condição. Contains(): verifica se um elemento específico existe na coleção. Any() é preferível a Count() > 0 por performance (short-circuit).
27
Qual a diferença entre First(), FirstOrDefault(), Single() e SingleOrDefault()?
First(): retorna o primeiro elemento; lança exceção se vazio. FirstOrDefault(): retorna o primeiro ou default(T) se vazio. Single(): retorna o único elemento; lança exceção se vazio ou se houver mais de um. SingleOrDefault(): retorna o único ou default(T) se vazio; lança se houver mais de um. Use Single quando espera exatamente um resultado.
28
O que são Generics em C#? Quais suas vantagens?
Generics permitem criar classes, métodos e interfaces parametrizados por tipo (ex: List, Dictionary). Vantagens: (1) Type safety em compile-time, (2) Eliminam boxing/unboxing, (3) Reusabilidade de código, (4) Performance superior a coleções não-genéricas. Constraints (where T : class, where T : notnull, where T : new()) restringem os tipos aceitos.
29
O que são Generic Constraints e quais existem?
Constraints restringem os tipos que podem ser usados como type arguments. Principais: where T : struct (value type), where T : class (reference type), where T : notnull (não-nulo), where T : new() (construtor sem parâmetros), where T : BaseClass (herança), where T : IInterface (implementa interface), where T : unmanaged. Podem ser combinadas.
30
Explique o padrão Strategy. Quando usá-lo?
Strategy define uma família de algoritmos, encapsula cada um e os torna intercambiáveis. Em C#: crie uma interface (ex: IPaymentStrategy) com o método do algoritmo, implemente em classes concretas (CreditCardPayment, PixPayment), e injete a estratégia desejada. Útil quando há múltiplas variações de um comportamento e você quer evitar if/else ou switch extensos.
31
Explique o padrão Factory. Quando usá-lo?
Factory encapsula a lógica de criação de objetos, permitindo que o código cliente não conheça as classes concretas. Simple Factory: método estático que retorna instância baseada em parâmetro. Factory Method: método virtual que subclasses sobrescrevem. Abstract Factory: família de objetos relacionados. Use quando a criação é complexa ou quando quer desacoplar o código de tipos concretos.
32
O que são os princípios SOLID?
S: Single Responsibility - uma classe deve ter apenas uma razão para mudar. O: Open/Closed - aberto para extensão, fechado para modificação. L: Liskov Substitution - subclasses devem ser substituíveis por suas bases. I: Interface Segregation - prefira interfaces específicas a uma genérica. D: Dependency Inversion - dependa de abstrações, não de implementações concretas.
33
Explique o princípio Single Responsibility (SRP) com exemplo.
SRP diz que uma classe deve ter apenas uma razão para mudar, ou seja, uma única responsabilidade. Exemplo: em vez de uma classe ReportGenerator que lê dados, calcula estatísticas E formata relatório, separe em: IDataReader (leitura), IStatisticsCalculator (cálculos), IReportFormatter (formatação). Cada classe pode evoluir independentemente.
34
O que é Dependency Injection (DI)? Quais os tipos?
DI é uma técnica onde dependências são fornecidas (injetadas) externamente em vez de criadas internamente. Tipos: (1) Constructor Injection (mais comum e recomendado), (2) Property/Setter Injection, (3) Method Injection. Em ASP.NET Core, o container DI nativo suporta: Transient (nova instância sempre), Scoped (por request), Singleton (instância única).
35
Qual a diferença entre Transient, Scoped e Singleton no container DI do ASP.NET Core?
Transient: nova instância criada a cada vez que o serviço é solicitado. Scoped: uma instância por escopo (geralmente por HTTP request). Singleton: uma única instância para toda a aplicação. Cuidado: nunca injete Scoped em Singleton (captive dependency). Use Transient para serviços leves e stateless; Scoped para DbContext; Singleton para caches e configurações.
36
O que é async/await em C#? Como funciona?
async marca um método como assíncrono; await suspende a execução até a Task completar, liberando a thread para outro trabalho. O método deve retornar Task, Task ou ValueTask. Não cria nova thread por si só. Útil para I/O bound operations (HTTP, DB, file). O compilador transforma o método em uma state machine. Sempre use 'await' e evite .Result ou .Wait() (risco de deadlock).
37
O que é Task.WhenAll e Task.WhenAny? Quando usar cada um?
Task.WhenAll: aguarda TODAS as tasks completarem; retorna quando todas terminarem. Ideal para executar múltiplas operações independentes em paralelo. Task.WhenAny: retorna assim que QUALQUER task completar. Útil para timeouts, cancelamento, ou processar resultados conforme ficam disponíveis. Ambos propagam exceções; WhenAll agrupa em AggregateException.
38
O que é CancellationToken e como usá-lo?
CancellationToken permite cancelamento cooperativo de operações assíncronas. Criado via CancellationTokenSource. O código verifica periodicamente token.IsCancellationRequested ou chama token.ThrowIfCancellationRequested(). Passe CancellationToken como parâmetro em métodos async. Em APIs, o framework fornece automaticamente via HttpContext.RequestAborted. Sempre propague o token para operações internas.
39
O que é IAsyncEnumerable? Quando usar?
IAsyncEnumerable (C# 8) permite iteração assíncrona com 'await foreach'. Diferente de Task> que retorna todos os itens de uma vez, IAsyncEnumerable produz itens sob demanda (streaming). Ideal para: queries de banco grandes, leitura de arquivos, APIs paginadas. Suporta CancellationToken via [EnumeratorCancellation] attribute.
40
O que é SemaphoreSlim? Para que serve?
SemaphoreSlim é uma primitiva de sincronização leve que limita o número de threads/tasks que podem acessar um recurso simultaneamente. Inicializado com contagem máxima. Métodos: Wait/WaitAsync (decrementa), Release (incrementa). Ideal para: limitar paralelismo em operações async (ex: máximo 5 requests HTTP simultâneos), throttling. É preferível ao Semaphore por ser mais leve.
41
O que é ReaderWriterLockSlim? Quando usar?
ReaderWriterLockSlim permite múltiplos leitores simultâneos OU um único escritor exclusivo. Métodos: EnterReadLock/ExitReadLock, EnterWriteLock/ExitWriteLock. Ideal quando leituras são muito mais frequentes que escritas (ex: cache). Mais eficiente que lock simples nesse cenário. Sempre use try-finally para garantir que o lock seja liberado.
42
O que é ConcurrentDictionary?
ConcurrentDictionary é uma coleção thread-safe do namespace System.Collections.Concurrent. Operações atômicas: TryAdd, TryRemove, TryUpdate, GetOrAdd, AddOrUpdate. Não requer locks externos. Ideal para caches e lookups compartilhados entre threads. GetOrAdd e AddOrUpdate aceitam factory delegates. Preferível a Dictionary + lock em cenários de alta concorrência.
43
Explique o padrão Circuit Breaker.
Circuit Breaker previne chamadas repetidas a serviços que estão falhando. Estados: Closed (normal), Open (falhas excederam threshold, rejeita chamadas), Half-Open (após timeout, permite uma chamada de teste). Se a chamada de teste suceder, volta a Closed; se falhar, volta a Open. Em C#, pode ser implementado manualmente ou com Polly. Protege contra cascading failures.
44
O que é retry com exponential backoff?
Retry com exponential backoff é uma estratégia onde, após uma falha, espera-se um tempo crescente antes de tentar novamente (ex: 1s, 2s, 4s, 8s). Evita sobrecarregar serviços em recuperação. Geralmente combinado com jitter (variação aleatória) para evitar thundering herd. Em C#, pode ser implementado com Polly ou manualmente. Defina max retries e max delay.
45
O que é AggregateException? Quando ocorre?
AggregateException é uma exceção que contém múltiplas exceções internas (InnerExceptions). Ocorre com Task.WhenAll, Parallel.ForEach, PLINQ. Para tratar: use .InnerExceptions para acessar cada exceção individual, ou .Flatten() para achatar exceções aninhadas, ou .Handle() para tratar seletivamente. Em async/await, o runtime desembrulha automaticamente a primeira exceção.
46
O que é xUnit? Quais os principais atributos?
xUnit é um framework de testes unitários para .NET. Atributos: [Fact] para testes sem parâmetros, [Theory] para testes parametrizados, [InlineData] para dados inline, [MemberData] para dados de propriedade/método, [ClassData] para dados de classe. Padrão AAA: Arrange, Act, Assert. IClassFixture para compartilhar contexto entre testes de uma classe.
47
O que são testes unitários vs integração vs aceitação?
Unitários: testam uma unidade isolada (método/classe), rápidos, sem dependências externas, usam mocks/fakes. Integração: testam interação entre componentes reais (ex: API + banco), mais lentos, usam containers ou in-memory DB. Aceitação: testam fluxos completos do ponto de vista do usuário, end-to-end. Pirâmide de testes: muitos unitários, menos integração, poucos aceitação.
48
O que é FluentAssertions? Por que usar?
FluentAssertions é uma biblioteca que fornece assertions legíveis e expressivas para testes. Em vez de Assert.Equal(expected, actual), escreve-se actual.Should().Be(expected). Vantagens: mensagens de erro mais claras, sintaxe natural, suporte a coleções (Should().Contain(), Should().HaveCount()), objetos (Should().BeEquivalentTo()), exceções (Should().Throw()).
49
O que é WebApplicationFactory? Para que serve em testes?
WebApplicationFactory cria um servidor de teste in-memory para testes de integração de APIs ASP.NET Core. Permite: testar endpoints HTTP sem servidor real, configurar serviços de teste (substituir DB, mock de serviços), acessar HttpClient para fazer requests. O pipeline completo (middleware, filters, routing) é exercitado. Ideal para testes de integração de APIs.
50
O que são Minimal APIs no ASP.NET Core?
Minimal APIs (ASP.NET Core 6+) permitem criar APIs HTTP com código mínimo, sem controllers. Usam app.MapGet/MapPost/MapPut/MapDelete diretamente no Program.cs. Suportam: parameter binding automático, filtros, agrupamento com MapGroup, OpenAPI/Swagger. Ideal para microserviços e APIs simples. Para APIs complexas, controllers tradicionais podem ser mais organizados.
51
Como implementar paginação em uma API REST?
Paginação usa query parameters como ?page=1&pageSize=10. Retorne: items da página, total de items, total de páginas, página atual. Use Skip/Take em LINQ: items.Skip((page-1)*pageSize).Take(pageSize). Retorne metadata em headers (X-Total-Count) ou no body. Cursor-based pagination (usando ID ou timestamp do último item) é mais eficiente para grandes datasets.
52
O que é JWT (JSON Web Token)? Como funciona em ASP.NET Core?
JWT é um token auto-contido com header (algoritmo), payload (claims) e signature. Fluxo: usuário autentica, servidor gera JWT, cliente envia JWT no header Authorization: Bearer . Em ASP.NET Core: configure AddAuthentication().AddJwtBearer(), valide issuer, audience, signing key e lifetime. Claims contêm roles e dados do usuário. Não armazene dados sensíveis no payload (é base64, não criptografado).
53
O que é role-based authorization em ASP.NET Core?
Role-based authorization restringe acesso baseado em roles do usuário. Configure com [Authorize(Roles = "Admin")] em endpoints. Roles são armazenadas como claims no JWT. Pode combinar com policy-based authorization para cenários mais complexos. AddAuthorization com AddPolicy permite criar políticas customizadas que verificam múltiplas condições.
54
O que é Entity Framework Core? Quais as abordagens?
EF Core é um ORM (Object-Relational Mapper) da Microsoft. Abordagens: Code-First (classes geram DB via migrations), Database-First (DB existente gera classes). Conceitos: DbContext (sessão com DB), DbSet (tabela), Fluent API (configuração detalhada), Data Annotations, Migrations. Suporta LINQ para queries. Padrões: Repository, Unit of Work.
55
Qual a diferença entre Fluent API e Data Annotations no EF Core?
Data Annotations: atributos decorativos nas classes ([Key], [Required], [MaxLength]). Simples mas limitados. Fluent API: configuração no OnModelCreating via ModelBuilder. Mais poderoso: suporta composite keys, configuração de relacionamentos complexos, owned types, conversões de valor. Fluent API tem precedência sobre Data Annotations. Prefira Fluent API para configurações complexas.
56
O que é o padrão Repository? Quais suas vantagens?
Repository abstrai o acesso a dados, fornecendo uma interface de coleção para o domínio. Interface: IRepository com métodos como GetById, GetAll, Add, Update, Delete. Vantagens: desacopla lógica de negócio do acesso a dados, facilita testes (mock do repository), centraliza queries. Crítica: pode ser uma abstração desnecessária sobre EF Core que já é um repository/UoW.
57
Qual a diferença entre ADO.NET e Dapper?
ADO.NET é o acesso de dados de baixo nível do .NET: SqlConnection, SqlCommand, SqlDataReader. Controle total mas verboso. Dapper é um micro-ORM que estende IDbConnection com métodos como Query, Execute, QueryFirst. Mapeia resultados para objetos automaticamente. Dapper é mais rápido que EF Core para leituras, próximo ao ADO.NET puro. Use Dapper quando performance é crítica.
58
O que são Stored Procedures? Vantagens e desvantagens?
Stored Procedures são blocos de SQL armazenados no banco de dados. Vantagens: performance (plano de execução cacheado), segurança (evitam SQL injection), reuso, encapsulam lógica complexa. Desvantagens: lógica fora do código C# (difícil versionar), testabilidade reduzida, vendor lock-in, podem esconder complexidade. Em C#: chamadas via ADO.NET ou Dapper com CommandType.StoredProcedure.
59
O que é SQL Injection e como prevenir em C#?
SQL Injection ocorre quando input do usuário é concatenado diretamente em queries SQL, permitindo execução de código malicioso. Prevenção: (1) SEMPRE use parâmetros (SqlParameter, @param em Dapper), (2) Use ORMs como EF Core que parametrizam automaticamente, (3) Valide e sanitize inputs, (4) Use stored procedures parametrizadas, (5) Princípio do menor privilégio no DB.
60
O que é o padrão Observer e como se relaciona com eventos em C#?
Observer define uma dependência um-para-muitos: quando o subject muda de estado, todos os observers são notificados. Em C#, eventos (event keyword) implementam Observer nativamente: a classe publisher (subject) declara o evento, classes subscriber (observers) registram handlers com +=. Vantagem sobre delegate puro: evento restringe acesso externo (só += e -= permitidos).
61
Explique Clean Code: quais princípios de nomenclatura seguir?
Nomes devem revelar intenção: use nomes descritivos e pronunciáveis. Classes/records: substantivos (OrderProcessor). Métodos: verbos (CalculateTotal). Interfaces: prefixo I (IPaymentStrategy). Booleanos: prefixo is/has/can (isValid). Evite: abreviações obscuras, nomes genéricos (data, temp), nomes com tipo (strName). Consistência: use o mesmo termo para o mesmo conceito em todo o codebase.
62
O que é method extraction e quando aplicar?
Method extraction é refatorar código longo em métodos menores e focados. Aplique quando: (1) método tem mais de 10-20 linhas, (2) há comentários explicando blocos de código, (3) código é duplicado, (4) há níveis de abstração misturados. Cada método deve fazer uma coisa e ter nome descritivo. Benefícios: legibilidade, testabilidade, reuso.
63
O que é a diferença entre 'string' e 'String' em C#?
São exatamente a mesma coisa. 'string' (minúsculo) é o alias C# para System.String. Convenção: use 'string' para declarar variáveis e 'String' para acessar métodos estáticos (String.IsNullOrEmpty), embora ambos funcionem em qualquer contexto. Strings são imutáveis e reference types (embora se comportem como value types na comparação de igualdade).
64
Explique imutabilidade em C#. Por que é importante?
Imutabilidade significa que o estado de um objeto não pode ser alterado após criação. Em C#: strings são imutáveis, records são imutáveis por padrão, propriedades init-only (init;), readonly fields, ImmutableList. Vantagens: thread-safety sem locks, previsibilidade, facilita debugging, segurança. Para modificar, cria-se uma nova instância (with expression em records).
65
O que é IDisposable e o padrão Dispose?
IDisposable define o método Dispose() para liberar recursos não-gerenciados (arquivos, conexões, handles). Use 'using' statement/declaration para garantir chamada automática. Padrão completo inclui: finalizer (~Classe), Dispose(bool), GC.SuppressFinalize. Em código moderno, prefira 'using declaration': using var conn = new SqlConnection(); que chama Dispose ao sair do escopo.
66
O que é o Garbage Collector (GC) no .NET?
O GC gerencia memória automaticamente, liberando objetos não referenciados. Usa gerações: Gen0 (novos, coletados frequentemente), Gen1 (intermediários), Gen2 (long-lived). Large Object Heap (LOH) para objetos >85KB. GC é não-determinístico. Não dependa de finalizers para liberar recursos críticos. Use IDisposable para recursos não-gerenciados. GC.Collect() raramente deve ser chamado manualmente.
67
O que são nullable reference types (NRT) em C#?
NRT (C# 8) permite anotar referências como nullable (string?) ou non-nullable (string). Ativado com enable no .csproj. O compilador emite warnings quando: variável non-nullable recebe null, variável nullable é usada sem verificação. Operadores: ?. (null-conditional), ?? (null-coalescing), ??= (null-coalescing assignment). NRT reduz NullReferenceExceptions.
68
O que é pattern matching avançado em C#?
C# evoluiu pattern matching significativamente: C# 7: type patterns (is Type t), constant patterns. C# 8: switch expressions, property patterns ({ Prop: value }), tuple patterns, positional patterns. C# 9: relational patterns (> 0, <= 100), logical patterns (and, or, not), type patterns simplificados. C# 11: list patterns ([1, 2, ..]). Permite código declarativo e expressivo.
69
O que é Middleware em ASP.NET Core?
Middleware são componentes que formam o pipeline de processamento de HTTP requests. Cada middleware pode: processar o request, passar para o próximo (next()), processar o response. Ordem importa: exceções primeiro, depois auth, depois routing. Exemplos: UseExceptionHandler, UseAuthentication, UseAuthorization, UseRouting, MapControllers. Custom middleware implementa RequestDelegate.
70
Explique o conceito de Thread Safety. Como garantir em C#?
Thread safety garante que código funciona corretamente quando acessado por múltiplas threads simultaneamente. Mecanismos: lock (Monitor), SemaphoreSlim, ReaderWriterLockSlim, Interlocked (operações atômicas), coleções concurrent (ConcurrentDictionary), imutabilidade. Preferências modernas: async/await evita threads manuais, coleções concurrent evitam locks explícitos, imutabilidade elimina problemas de compartilhamento de estado.
71
O que é deadlock? Como prevenir em C#?
Deadlock ocorre quando duas ou mais threads esperam eternamente por recursos que a outra possui. Causas comuns em C#: (1) .Result/.Wait() em código async (deadlock de contexto de sincronização), (2) Múltiplos locks adquiridos em ordens diferentes. Prevenção: use async/await (nunca .Result), adquira locks sempre na mesma ordem, use timeout nos locks, prefira SemaphoreSlim a lock para código async.
72
O que é race condition? Como evitar?
Race condition ocorre quando o resultado depende da ordem/timing de execução de threads. Exemplo: duas threads incrementando um contador podem perder incrementos. Soluções: (1) lock/Monitor para seções críticas, (2) Interlocked para operações atômicas simples, (3) ConcurrentDictionary para coleções, (4) SemaphoreSlim para limitar acesso, (5) Imutabilidade. Sempre proteja estado compartilhado mutável.
73
O que são characterization tests? Para que servem?
Characterization tests (testes de caracterização) documentam o comportamento ATUAL de código legado antes de refatorar. Você escreve testes que passam com o código existente, capturando inclusive bugs. Depois, ao refatorar, esses testes garantem que o comportamento não mudou inadvertidamente. São uma rede de segurança para refatoração. Após refatorar, converta-os em testes unitários adequados.
74
O que é FluentValidation? Quando usar?
FluentValidation é uma biblioteca para criar regras de validação usando sintaxe fluente. Crie uma classe que herda AbstractValidator e defina regras no construtor: RuleFor(x => x.Nome).NotEmpty().MaximumLength(100). Suporta: validação condicional (When/Unless), validação customizada (Must), mensagens personalizadas. Integra com ASP.NET Core via AddFluentValidation. Use para validação complexa de DTOs.
75
O que é uma arquitetura em camadas (layered architecture)?
Organiza o código em camadas com responsabilidades específicas: (1) Presentation (API/Controllers), (2) Application/Service (lógica de aplicação, orquestração), (3) Domain (entidades, regras de negócio), (4) Infrastructure (DB, serviços externos). Cada camada só depende da camada abaixo. Variações: Clean Architecture inverte dependências com o Domain no centro. Benefícios: separação de concerns, testabilidade.
76
Qual a diferença entre Task e Thread em C#?
Thread é uma unidade de execução do SO, pesada (1MB de stack). Task é uma abstração de nível mais alto que pode ou não usar threads. Task usa o ThreadPool (threads reutilizáveis). Para I/O async, Tasks não consomem threads durante a espera. Prefira Task.Run para CPU-bound work, async/await para I/O-bound. Nunca crie Threads diretamente em código moderno.
77
O que é o ThreadPool em .NET?
ThreadPool mantém um conjunto de threads reutilizáveis para executar trabalho de curta duração. Task.Run e async/await usam ThreadPool internamente. Evita o custo de criar/destruir threads. Tamanho ajusta-se dinamicamente. Não use ThreadPool para trabalho de longa duração (bloqueia threads para outros). Configurável com ThreadPool.SetMinThreads/SetMaxThreads, mas raramente necessário.
78
Explique LINQ GroupBy com exemplo prático.
GroupBy agrupa elementos por uma chave. Retorna IEnumerable>. Exemplo: produtos.GroupBy(p => p.Categoria) retorna grupos onde Key é a categoria e cada grupo contém os produtos daquela categoria. Pode-se combinar com Select para projetar resultados: .GroupBy(p => p.Cat).Select(g => new { Cat = g.Key, Media = g.Average(p => p.Preco) }).
79
O que é o operador 'nameof' em C#?
nameof retorna o nome de uma variável, tipo ou membro como string em compile-time. Exemplo: nameof(customer.Name) retorna "Name". Vantagens: refactoring-safe (renomear atualiza automaticamente), sem strings mágicas. Usos: ArgumentNullException(nameof(param)), INotifyPropertyChanged, logging, validação. Não tem custo em runtime.
80
O que é 'yield return' e como funciona?
yield return permite criar iteradores (IEnumerable) de forma lazy. O método é executado sob demanda: cada chamada a MoveNext() executa até o próximo yield return. O estado é preservado entre chamadas. yield break encerra a iteração. Benefícios: economia de memória (não materializa toda a coleção), composição com LINQ. Não pode ser usado em blocos try-catch com catch.
81
Explique a diferença entre IEnumerable e IQueryable.
IEnumerable: executa queries em memória (LINQ to Objects), usa delegates. IQueryable: traduz queries para o provider (SQL, etc), usa expression trees. IQueryable permite que o DB execute filtros/ordenação. Erro comum: chamar ToList() cedo e filtrar em memória. Use IQueryable para queries contra DB (EF Core) e IEnumerable para coleções em memória.
82
O que são Expression Trees em C#?
Expression trees representam código como dados (árvore de nós). LINQ providers (EF Core) analisam expression trees para traduzir C# em SQL. Exemplo: Expression> é uma árvore analisável, enquanto Func é um delegate compilado. Expression trees permitem inspeção e tradução de código em runtime. São a base do IQueryable.
83
O que são Tuples em C# e quando usá-las?
Tuples (C# 7) permitem retornar múltiplos valores sem criar classes: (string Name, int Age) GetPerson(). Acessados por nome ou Item1/Item2. ValueTuple (struct) é preferível ao antigo Tuple<> (class). Use para: retornos múltiplos em métodos privados, decomposição com var (name, age) = GetPerson(). Evite em APIs públicas; prefira classes/records para legibilidade.
84
O que é Dependency Inversion Principle (DIP)?
DIP é o D do SOLID: módulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações. Abstrações não devem depender de detalhes. Em C#: a camada de negócio depende de IRepository (abstração), não de SqlRepository (detalhe). A implementação concreta é injetada via DI container. Resultado: código desacoplado e testável.
85
O que é o princípio Open/Closed (OCP)? Exemplo em C#.
OCP: classes devem ser abertas para extensão, fechadas para modificação. Em vez de modificar código existente com if/else para novos comportamentos, use polimorfismo. Exemplo: em vez de if(tipo == "credito") ... else if(tipo == "pix"), crie IPaymentStrategy com implementações CreditPayment e PixPayment. Adicionar novo pagamento = criar nova classe, sem alterar código existente.
86
O que é Interface Segregation Principle (ISP)?
ISP: clientes não devem depender de interfaces que não usam. Em vez de uma interface grande IWorker com Work(), Eat(), Sleep(), crie IWorkable com Work() e IFeedable com Eat(). Robôs implementam IWorkable; humanos implementam ambas. Benefícios: coesão, classes implementam apenas o necessário, mudanças em uma interface não afetam implementações não relacionadas.
87
O que é Liskov Substitution Principle (LSP)?
LSP: objetos de uma classe derivada devem ser substituíveis por objetos da classe base sem alterar a correção do programa. Violação clássica: Quadrado herda de Retângulo (alterar largura do quadrado deve alterar altura, quebrando expectativas). Em C#: subclasses não devem lançar exceções inesperadas, enfraquecer pós-condições ou fortalecer pré-condições.
88
O que é 'var' em C#? Quando usar?
'var' é inferência de tipo em compile-time (não é dinâmico). O tipo é determinado pela expressão do lado direito. Use quando o tipo é óbvio: var list = new List(). Evite quando obscurece o tipo: var result = GetData() (qual o tipo?). Nunca é dynamic; é fortemente tipado. var é obrigatório para anonymous types: var x = new { Name = "Ana" }.
89
O que é 'dynamic' em C#? Diferença para 'var'.
'dynamic' resolve tipos em runtime (late binding), 'var' resolve em compile-time. dynamic não tem IntelliSense nem verificação de tipo em compilação; erros só aparecem em runtime. Usos: interop COM, reflection, ExpandoObject, JSON dinâmico. Evite dynamic em código geral; prefira tipos fortes. Performance inferior devido à resolução em runtime.
90
Como funciona o operador '??' (null-coalescing) e '??=' em C#?
?? retorna o operando esquerdo se não-null, senão o direito: string nome = input ?? "padrão". ??= atribui o valor do lado direito somente se o lado esquerdo for null: list ??= new List() (equivale a list = list ?? new List()). Podem ser encadeados: a ?? b ?? c. Úteis para valores padrão e inicialização lazy.
91
O que são init-only properties em C#?
init (C# 9) permite que propriedades sejam definidas apenas durante a inicialização do objeto (construtor ou object initializer). Após isso, tornam-se read-only. Exemplo: public string Nome { get; init; }. Diferente de 'set' (permite modificação a qualquer momento) e de read-only (get; sem set, só definível no construtor). Ideal para objetos semi-imutáveis.
92
O que são top-level statements em C#?
Top-level statements (C# 9) permitem escrever código diretamente no arquivo sem classe Program ou método Main explícito. O compilador gera a estrutura automaticamente. Simplifica programas simples e scripts. Limitação: apenas um arquivo pode ter top-level statements. args está disponível implicitamente. Em .NET 6+, o template padrão usa top-level statements.
93
Explique o conceito de 'hand-rolled fakes' vs mocking frameworks em testes.
Hand-rolled fakes são implementações manuais de interfaces criadas para testes (ex: FakeEmailSender implementa IEmailSender armazenando mensagens em lista). Mocking frameworks (Moq, NSubstitute) geram implementações dinamicamente. Fakes: mais controle, mais código, mais legíveis. Mocks: menos código, setup flexível, podem ser frágeis. Para testes simples, fakes manuais são preferíveis.
94
O que é Test-Driven Development (TDD)?
TDD é a prática de escrever testes ANTES do código de produção. Ciclo Red-Green-Refactor: (1) Red: escreva um teste que falha, (2) Green: escreva o código mínimo para passar, (3) Refactor: melhore o código mantendo os testes passando. Benefícios: design guiado por uso, cobertura alta, confiança para refatorar. Nem sempre prático, mas valioso para lógica de negócio complexa.
95
O que é o padrão AAA (Arrange-Act-Assert) em testes?
AAA organiza testes em 3 seções: Arrange (configurar dados e dependências), Act (executar a ação sendo testada), Assert (verificar o resultado). Cada teste deve testar uma coisa. Exemplo: [Fact] void DeveCalcularTotal() { var pedido = new Pedido(...); /*Arrange*/ var total = pedido.CalcularTotal(); /*Act*/ total.Should().Be(100); /*Assert*/ }.
96
O que é o padrão Given/When/Then em testes?
Given/When/Then é o equivalente BDD do AAA: Given (pré-condições), When (ação), Then (resultado esperado). Focado na perspectiva do comportamento. Exemplo: Given um usuário autenticado, When ele acessa /admin, Then recebe status 200. Usado em testes de aceitação e integração. Frameworks como SpecFlow formalizam esse padrão.
97
Qual a diferença entre 'const' e 'readonly' em C#?
'const': valor definido em compile-time, implicitamente estático, deve ser literal (números, strings, null). 'readonly': valor definido em runtime, pode ser atribuído no construtor, funciona com qualquer tipo. 'static readonly': similar a const mas com flexibilidade de runtime. Use const para valores verdadeiramente constantes; readonly para valores que dependem de configuração ou cálculo.
98
O que são Span e Memory?
Span é uma ref struct que representa uma fatia contígua de memória (array, stack, memória nativa) sem alocação. Não pode ser usado em contextos async (stack-only). Memory é similar mas pode ser armazenado na heap (funciona com async). Ambos evitam cópias desnecessárias. Usados para parsing de strings, processamento de buffers. Melhoram performance significativamente.
99
O que é source generator em C#?
Source generators (C# 9/.NET 5) geram código C# em compile-time. Analisam o código existente e produzem código adicional sem runtime reflection. Usos: serialização JSON (System.Text.Json), regex compilada, DI registration, mapeamento de objetos. Benefícios: performance (sem reflection), erros em compile-time, IntelliSense para código gerado.
100
O que é o HttpClient e como usá-lo corretamente?
HttpClient é a classe para fazer requisições HTTP. Problema: criar instância por request causa socket exhaustion. Solução: IHttpClientFactory (registrado via AddHttpClient()). Variações: typed clients (classe com HttpClient injetado), named clients. Sempre use async (GetAsync, PostAsJsonAsync). Configure timeouts e headers. Use Polly para retry/circuit breaker com AddPolicyHandler.
101
O que são Value Objects no Domain-Driven Design?
Value Objects são objetos definidos por seus atributos, sem identidade. Exemplos: Email, CPF, Dinheiro, Endereço. Dois Value Objects com mesmos valores são iguais. Em C#: implemente com records (igualdade por valor built-in) ou structs. Validação no construtor. Imutáveis. Diferente de Entidades que têm identidade (Id) e podem mudar ao longo do tempo.
102
O que é o padrão Options em ASP.NET Core?
O padrão Options permite acessar configurações tipadas via DI. Configure com services.Configure(config.GetSection("MinhaSecao")). Injete como IOptions (singleton), IOptionsSnapshot (scoped, recarrega), IOptionsMonitor (singleton, notifica mudanças). Valide com ValidateDataAnnotations() ou ValidateOnStart(). Evite injetar IConfiguration diretamente.
103
O que é middleware de tratamento global de exceções em ASP.NET Core?
Middleware de exceções captura exceções não tratadas no pipeline. Em Minimal APIs: app.UseExceptionHandler() ou middleware customizado. Converta exceções em Problem Details (RFC 7807) com status code apropriado. Mapeie exceções de domínio para HTTP status codes: NotFoundException → 404, ValidationException → 400, UnauthorizedException → 401. Log a exceção original.
104
Explique a diferença entre 'sealed' e 'abstract' em C#.
'abstract' impede instanciação direta e obriga subclasses a implementar membros abstract. Projetada para herança. 'sealed' impede que uma classe seja herdada. Benefícios de sealed: clareza de intenção, otimização de performance (o JIT pode devirtualizar chamadas). Use sealed por padrão em classes que não foram projetadas para herança. Records são sealed por padrão.
105
O que é covariance e contravariance em C# generics?
Covariance (out T): permite usar um tipo mais derivado que o especificado. IEnumerable: IEnumerable é atribuível a IEnumerable. Contravariance (in T): permite usar um tipo menos derivado. Action: Action é atribuível a Action. Covariance é para saída (retornos), contravariance para entrada (parâmetros). Aplica-se a interfaces e delegates genéricos.
106
Quais são as principais novidades do C# 10, 11 e 12?
C# 10: global using, file-scoped namespaces, record structs. C# 11: raw string literals, required members, list patterns, generic math. C# 12: primary constructors para classes, collection expressions ([1,2,3]), alias any type, default lambda parameters. Cada versão aumenta expressividade e reduz boilerplate, mantendo backward compatibility.
107
O que são Global Usings e File-Scoped Namespaces?
Global usings (C# 10): 'global using System.Linq;' aplica o using a todos os arquivos do projeto. Implicit usings no SDK adicionam namespaces comuns automaticamente. File-scoped namespaces: 'namespace MeuApp;' (sem chaves) reduz indentação. Ambos reduzem boilerplate. Configure implicit usings no .csproj com enable.
108
O que é o operador 'with' em C# records?
O operador 'with' cria uma cópia de um record com algumas propriedades alteradas: var novoUsuario = usuario with { Nome = "Ana" }. Essencial para imutabilidade: em vez de modificar o objeto, cria-se um novo. Funciona com records (class e struct). Copia todas as propriedades e aplica as alterações especificadas. Análogo a spread operator em JavaScript.
109
Como funciona o pattern matching com switch expression?
Switch expression retorna um valor e usa pattern matching: var resultado = forma switch { Circulo c => Math.PI * c.Raio * c.Raio, Retangulo { Largura: var l, Altura: var a } => l * a, _ => throw new ArgumentException() }. Suporta: type patterns, property patterns, tuple patterns, when clauses, discard (_) como default. Mais conciso que switch statement.
110
O que são Primary Constructors em C# 12?
Primary constructors permitem declarar parâmetros diretamente na declaração de classe/struct: class UserService(IUserRepository repo, ILogger logger). Os parâmetros ficam disponíveis em toda a classe. Diferente de records: não geram propriedades públicas automaticamente. Reduzem boilerplate de DI. Os parâmetros são capturados como campos privados implícitos.
111
O que é Minimal API vs Controller-based API? Quando usar cada?
Minimal APIs: menos cerimônia, declarativas, ideais para microserviços simples e poucos endpoints. Controllers: mais estruturados, suportam filtros complexos, model binding avançado, áreas, ideais para APIs grandes. Minimal APIs ganharam paridade de features (filters, groups, OpenAPI). Escolha baseada no tamanho do projeto e preferência da equipe. Ambos podem coexistir.
112
O que é o padrão CQRS (Command Query Responsibility Segregation)?
CQRS separa operações de leitura (Queries) das de escrita (Commands). Cada lado pode ter modelos, repositórios e até bancos diferentes otimizados para seu propósito. Commands alteram estado e não retornam dados. Queries retornam dados sem alterar estado. Benefícios: otimização independente, escalabilidade. Complexidade adicional; use apenas quando leituras e escritas têm requisitos muito diferentes.
113
O que é o padrão Mediator? Como se relaciona com MediatR?
Mediator promove acoplamento fraco: objetos se comunicam através de um mediador central. MediatR é uma biblioteca .NET que implementa Mediator com IRequest/IRequestHandler. Request é enviado ao Mediator que roteia para o handler correto. Pipelines behaviors permitem cross-cutting concerns (logging, validação, transação). Popular em CQRS. Cuidado: pode obscurecer o fluxo do código.
114
O que é um Anti-Pattern Captive Dependency?
Captive Dependency ocorre quando um serviço com lifetime longo (Singleton) depende de um com lifetime curto (Scoped ou Transient). O serviço Scoped fica 'capturado' como Singleton, causando bugs. Exemplo: Singleton capturando DbContext Scoped faz o DbContext ser compartilhado entre requests. Solução: use IServiceScopeFactory para criar escopos sob demanda dentro de Singletons.