TOP 50 pytań rekrutacyjnych
Junior .NET Developer
Zebrane z realnych rozmów kwalifikacyjnych. Każde pytanie ma wzorcową odpowiedź — taką, której rekruter naprawdę szuka.
7 kategorii — pełne pokrycie rozmowy technicznej
C# Podstawy
Pytania Q01–Q10 · typy, class vs struct, nullable reference types, async/await, pattern matching.
OOP & SOLID
Pytania Q11–Q20 · cztery filary OOP, pięć zasad SOLID, interfejsy i abstrakcje.
ASP.NET Core & Web API
Pytania Q21–Q30 · middleware, routing, dependency injection, cykl życia żądania.
EF Core & bazy danych
Pytania Q31–Q37 · problem N+1, migracje, tracking, optymalizacja zapytań.
Wzorce & architektura
Pytania Q38–Q43 · Repository Pattern, Clean Architecture, CQRS i wzorce projektowe.
Testowanie
Pytania Q44–Q47 · testy jednostkowe, TDD, mockowanie i dobre praktyki testowe.
Git, DevOps & dobre praktyki
Pytania Q48–Q50 · kontrola wersji, CI/CD i standardy pracy w zespole.
Przykładowe pytania z listy
Kliknij, żeby zobaczyć, o co naprawdę pyta rekruter.
Q01 Jaka jest różnica między class a struct? ▾
struct faktycznie ma sens. Pełną wzorcową odpowiedź z kodem znajdziesz w materiale TOP 50.Q07 Jak działa async/await w C#? ▾
Task, kontynuacjach i o tym, dlaczego async void to problem. W materiale: odpowiedź wzorcowa + typowe pułapki.Q14 Wymień i omów cztery filary OOP ▾
Q18 Na czym polega pięć zasad SOLID? ▾
Q24 Czym jest middleware w ASP.NET Core? ▾
Q33 Czym jest problem N+1 w EF Core i jak go rozwiązać? ▾
Include, projekcje do DTO i kiedy lazy loading robi więcej szkody niż pożytku.Q40 Wyjaśnij Repository Pattern i Clean Architecture ▾
To tylko 7 z 50 pytań. Pozostałe 43 — wraz z pełnymi wzorcowymi odpowiedziami i kodem — czekają poniżej.
Chcę pełną listę 50 pytań ↓Pełna lista 50 pytań z odpowiedziami
TOP 50 Pytań Rekrutacyjnych
Junior .NET Developer
Zebrane z realnych rozmów kwalifikacyjnych. Każde pytanie ma wzorcową odpowiedź — taką, której rekruter naprawdę szuka.
class a struct w C#?
łatwe
+class to typ referencyjny — obiekt żyje na stercie (heap), zmienna przechowuje referencję. struct to typ wartościowy — dane leżą na stosie (stack) lub inline w obiekcie nadrzędnym, kopiowane przez wartość przy przypisaniu.
Vector2, Color, DateTime. Unikaj struct większych niż ~16 bajtów lub mutowalnych — kopiowanie jest kosztowne i podatne na błędy.nullable reference type i jak działa w C# 8+?
łatwe
+Od C# 8 typy referencyjne są domyślnie non-nullable. Kompilator ostrzega, gdy możliwy jest NullReferenceException. Dodanie ? jawnie oznacza, że zmienna może być null.
<Nullable>enable</Nullable> w .csproj. Eliminuje całą klasę błędów runtime zanim trafią na produkcję.async/await i jak działa pod spodem?
średnie
+async/await to lukier składniowy (syntactic sugar) na maszynę stanów generowaną przez kompilator. Przy pierwszym await, który nie jest gotowy, metoda zwraca kontrolę do wywołującego. Jeśli w danym momencie istnieje SynchronizationContext (np. WPF, WinForms, klasyczny ASP.NET), kontynuacja domyślnie do niego wraca — w przeciwnym razie (m.in. w ASP.NET Core i aplikacjach konsolowych) wraca po prostu na wątek z puli.
.Result / .Wait() z async — grozi deadlockiem tam, gdzie istnieje SynchronizationContext (klasyczny ASP.NET, WPF, WinForms). Jeśli async, to async przez cały callstack.SynchronizationContext — więc klasyczny deadlock z .Result opisany w podręcznikach do ASP.NET (System.Web) tu nie wystąpi z tego samego powodu. ConfigureAwait(false) wciąż jest dobrą praktyką w kodzie bibliotecznym (mniejszy narzut, przenośność), ale w ASP.NET Core nie chroni przed deadlockiem — chroni przed niepotrzebnym marshalingiem kontekstu.IEnumerable<T>, ICollection<T> a IList<T>?
łatwe
+IEnumerable<T> — tylko do odczytu, leniwa iteracja, brak Count. ICollection<T> dodaje Count, Add, Remove. IList<T> dodaje dostęp indeksowany oraz Insert/RemoveAt.
IEnumerable<T> (najwęższy wystarczający kontrakt — nie wymuszasz konkretnej kolekcji na wywołującym), pola prywatne jako List<T> (konkretna implementacja).Select, Where a FirstOrDefault?
łatwe
+LINQ to deklaratywny mechanizm zapytań do dowolnych źródeł danych (kolekcje, bazy danych, XML). Operatory są leniwe — wykonują się dopiero przy pierwszej enumeracji.
foreach, ToList(), Count().record w C# 9+ i kiedy go używać?
średnie
+record to typ referencyjny z wbudowaną semantyką wartości: auto-generowane Equals, GetHashCode i ToString oparte na właściwościach, nie referencji. Kompilator generuje też wyrażenie with do tworzenia niemutowalnych kopii.
delegate, Action, Func i Predicate?
średnie
+delegate to typowany wskaźnik na metodę. Action<T>, Func<T,TResult>, Predicate<T> to gotowe, wbudowane delegaty — nie trzeba deklarować własnych.
Garbage Collector w .NET i co to są generacje?
średnie
+GC w .NET jest generacyjny — obiekty podzielone na Gen0, Gen1, Gen2 oraz Large Object Heap (LOH, ≥85 KB). Gen0 jest zbierana najczęściej i najszybciej (krótko żyjące obiekty). Obiekty, które przeżyją kolekcję, trafiają do Gen1, a następnie do Gen2.
using / await using dla IDisposable. Unikaj wymuszania kolekcji (GC.Collect()) — prawie zawsze błąd projektowy.string od StringBuilder?
łatwe
+string jest niemutowalny — każda konkatenacja tworzy nowy obiekt na stercie. W pętli o n iteracjach to n alokacji (O(n)), ale każda kolejna kopiuje cały dotychczasowy string — więc łączny koszt kopiowania danych rośnie do O(n²). StringBuilder mutuje wewnętrzny bufor (z realokacją co jakiś czas) — O(n) alokacji i O(n) łącznego kosztu kopiowania.
pattern matching w C# i jakie są jego formy?
średnie
+Pattern matching pozwala testować kształt i wartości danych w wyrażeniach is, switch i switch expression. C# 9/10 dodał wzorce relacyjne, logiczne i wzorce właściwości.
Enkapsulacja — ukrywanie stanu, dostęp przez publiczne API. Dziedziczenie — współdzielenie kodu przez hierarchię klas. Polimorfizm — ten sam interfejs, różne zachowanie. Abstrakcja — modelowanie esencji domeny, ukrywanie szczegółów implementacji.
Klasa powinna mieć jeden powód do zmiany — jeden obszar odpowiedzialności. “Jeden powód” to jeden aktor biznesowy, który może zażądać zmiany logiki.
Kod powinien być otwarty na rozszerzenie, zamknięty na modyfikację. Nowe zachowania dodajemy przez nowe klasy/implementacje, nie przez zmianę istniejącego kodu.
DIP (zasada) — moduły wysokiego poziomu nie zależą od modułów niskiego poziomu; obie strony zależą od abstrakcji. DI (technika) — mechanizm dostarczania zależności z zewnątrz. DI jest sposobem realizacji DIP.
abstract class a interface? Kiedy użyć którego?
łatwe
+Klasa abstrakcyjna może mieć stan, konstruktory i konkretne metody — wyraża relację “jest”. Interfejs definiuje kontrakt zachowania — wyraża relację “potrafi”. Klasa może implementować wiele interfejsów, ale dziedziczyć tylko z jednej klasy.
Obiekt podklasy powinien być w stanie zastąpić obiekt klasy bazowej bez zmiany poprawności programu. Naruszenie objawia się rzucaniem wyjątków w nadpisanych metodach lub zawężaniem kontraktu.
Klient nie powinien być zmuszony do zależności od metod, których nie używa. Duże interfejsy rozbijamy na mniejsze, wyspecjalizowane.
Dziedziczenie (is-a) tworzy silne powiązanie hierarchiczne. Kompozycja (has-a) składa obiekt z mniejszych, wymiennych części. Zasada z GoF: “favor composition over inheritance”.
sealed i kiedy jej używać?
łatwe
+sealed blokuje dziedziczenie z klasy (lub nadpisywanie metody wirtualnej). Daje kompilatorowi i JIT więcej możliwości optymalizacji (devirtualization), dokumentuje intencję projektową i chroni przed nieoczekiwanym rozszerzaniem.
override vs new w kontekście metod?
średnie
+override — nadpisuje wirtualną metodę klasy bazowej. Wywołanie przez referencję bazową uruchamia wersję z klasy pochodnej (polimorfizm runtime). new — ukrywa metodę bazową. Wywołanie przez referencję bazową uruchamia wersję bazową.
new zamiast override łamie polimorfizm. Używaj new tylko świadomie, gdy celowo chcesz ukryć metodę bez polimorficznego zachowania.Żądanie przechodzi przez pipeline middleware — łańcuch komponentów, z których każdy może przetworzyć żądanie i/lub odpowiedź albo przekazać dalej przez wywołanie next().
Transient, Scoped i Singleton w DI?
łatwe
+Transient — nowa instancja przy każdym pobraniu z kontenera. Scoped — jedna instancja na żądanie HTTP. Singleton — jedna instancja przez całe życie aplikacji.
DbContext w Singleton to klasyczny przykład wycieku.InvalidOperationException przy starcie tylko gdy ValidateScopes jest włączone — a to jest domyślnie ustawione tylko w środowisku Development (WebApplicationBuilder włącza ValidateScopes i ValidateOnBuild automatycznie w Development). Na produkcji, jeśli nie ustawisz tego jawnie, wyjątku nie będzie — Scoped po prostu zacznie po cichu wyciekać, co jest dużo groźniejsze niż szybki fail-fast. Jawne wymuszenie walidacji też na produkcji: builder.Host.UseDefaultServiceProvider(o => { o.ValidateScopes = true; o.ValidateOnBuild = true; });Używamy IActionResult / ActionResult<T> i pomocniczych metod z ControllerBase.
[ApiController] automatycznie zwraca 400 z detalami, gdy ModelState.IsValid == false. Data Annotations to proste atrybuty wbudowane w .NET — dla złożonej walidacji używamy FluentValidation.
JWT (JSON Web Token) składa się z trzech części: header.payload.signature. Serwer generuje token po zalogowaniu użytkownika; klient wysyła go w nagłówku Authorization: Bearer <token>. ASP.NET Core weryfikuje podpis i claims automatycznie.
IHostedService i BackgroundService?
średnie
+IHostedService to interfejs dla usług startujących i zatrzymujących się razem z aplikacją. BackgroundService to klasa bazowa upraszczająca implementację długo działających workerów.
DbContext) wstrzykuj przez IServiceScopeFactory, nigdy bezpośrednio.Options Pattern i dlaczego jest lepszy od IConfiguration?
średnie
+Options Pattern silnie typuje konfigurację, umożliwia walidację przy starcie i ułatwia testowanie — nie przekazujemy surowego IConfiguration w głąb kodu.
Problem Details i jak ujednolicić obsługę błędów w API?
średnie
+RFC 9457 (Problem Details) to standard odpowiedzi błędów HTTP API. ASP.NET Core 8 wprowadził wbudowany globalny exception handler, zastępując ręczne middleware z try/catch.
Minimal APIs i kiedy użyć ich zamiast kontrolerów?
łatwe
+Minimal APIs (ASP.NET Core 6+) rejestrują endpointy bezpośrednio w Program.cs bez kontrolerów. Mniej boilerplate, lepsza wydajność, świetne dla mikrousług i małych API.
CORS (Cross-Origin Resource Sharing) — przeglądarka blokuje żądania JavaScript do innej domeny. Serwer musi jawnie zezwolić przez nagłówki odpowiedzi.
AllowAnyOrigin() + AllowCredentials() = błąd runtime. Przeglądarki nie wysyłają danych uwierzytelniających do wildcard origin.Problem N+1 — zamiast jednego zapytania z JOIN, wykonujemy 1 zapytanie po listę + N dodatkowych zapytań dla każdego elementu. Demoluje wydajność przy większych danych.
optionsBuilder.LogTo(Console.WriteLine). Zobaczysz każdy SELECT.Migracje to kod C# opisujący zmiany schematu bazy danych. Generowane automatycznie z modelu, mogą być wykonywane przez EF lub ręcznie jako skrypt SQL.
MigrateAsync() bezpośrednio na produkcji.AsNoTracking() i kiedy go używać?
łatwe
+Domyślnie EF Core śledzi zmiany w załadowanych encjach (Change Tracker). AsNoTracking() wyłącza śledzenie — szybsze zapytania, mniejsze zużycie pamięci. Stosuj dla operacji tylko do odczytu.
DbContext i dlaczego powinien być Scoped?
średnie
+DbContext nie jest thread-safe i reprezentuje wzorzec Unit of Work — śledzi zmiany w ramach jednej operacji biznesowej. Scoped = jeden kontekst na żądanie HTTP.
Repository Pattern i czy zawsze warto go stosować z EF Core?
średnie
+Repository abstrakcjonizuje dostęp do danych — ułatwia testowanie i pozwala zmienić ORM bez dotykania logiki biznesowej. Kontrowersja: DbContext sam realizuje już wzorce Unit of Work i Repository.
DbContext w serwisach jest akceptowalny. Dla dużych — Repository + Unit of Work dają testowalność i izolację warstwy danych.LINQ jest pierwszym wyborem. Raw SQL stosujemy gdy: LINQ generuje nieefektywne zapytanie, potrzebujemy zaawansowanych funkcji SQL (CTE, window functions) lub optymalizujemy krytyczną ścieżkę wydajnościową.
$"...{variable}" w FromSql.Optimistic Locking — zakładamy brak konfliktu, weryfikujemy przy zapisie przez RowVersion/ETag. Pessimistic Locking — blokujemy rekord na czas transakcji (SELECT FOR UPDATE). EF Core wspiera optymistyczne blokowanie natywnie przez [Timestamp].
Repository + Unit of Work.
średnie
+Repository izoluje dostęp do danych. Unit of Work grupuje wiele operacji w jedną atomową transakcję — albo wszystkie się udają, albo wszystkie są cofane.
Mediator i jak go używać z MediatR?
średnie
+Mediator oddziela nadawców od odbiorców — żądania/zdarzenia przechodzą przez centralny bus. MediatR + CQRS to popularny fundament Clean Architecture w ekosystemie .NET.
IPipelineBehavior-podobnym wzorcu (kilkadziesiąt linii kodu, zero zależności) albo bibliotekę Mediator (source generator, bez narzutu refleksji, w pełni darmowa) — zwłaszcza jeśli pipeline behaviors nie są realnie wykorzystywane, a mediator służy tylko jako cienka warstwa dispatchująca.Clean Architecture (Robert C. Martin) organizuje kod w koncentryczne warstwy z regułą zależności (Dependency Rule): zależności wskazują wyłącznie do środka. Warstwy wewnętrzne nie wiedzą nic o zewnętrznych.
Factory i kiedy go używać?
łatwe
+Factory enkapsuluje logikę tworzenia obiektów. Używamy gdy: tworzenie jest złożone lub zawiera reguły biznesowe, musimy wybrać konkretny typ w runtime, lub chcemy ukryć szczegóły konstruktora.
Decorator i gdzie jest stosowany w .NET?
średnie
+Decorator owija istniejący obiekt, dodając nowe zachowanie bez modyfikowania klasy bazowej. Doskonały do cross-cutting concerns: caching, logowanie, retry, pomiar czasu.
Result Pattern i kiedy jest lepszy od wyjątków?
trudne
+Result Pattern jawnie komunikuje sukces lub błąd przez typ zwracany, zamiast rzucać wyjątki dla przewidywalnych scenariuszy. Wyjątki są kosztowne i utrudniają śledzenie przepływu sterowania.
Unit test — testuje izolowaną jednostkę kodu, zależności mockowane. Szybki, deterministyczny. Integration test — testuje współpracę komponentów (np. kod + baza danych). E2E — symuluje użytkownika przez cały system (Playwright, Selenium).
Stub — zwraca predefiniowane dane, nie weryfikuje wywołań. Mock — weryfikuje, że metoda została wywołana z właściwymi argumentami. Fake — działająca, uproszczona implementacja (np. baza in-memory).
WebApplicationFactory<T> uruchamia in-process prawdziwy serwer ASP.NET Core — pełny pipeline middleware, DI, routing. Bez mockowania HTTP. Bazę danych wymieniamy na in-memory lub Testcontainers.
AAA to struktura testu: przygotuj dane → wykonaj akcję → zweryfikuj wynik. Czytelny test = żywa dokumentacja zachowania kodu.
result.Should().Be(90) zamiast Assert.Equal(90, result).git merge a git rebase?
średnie
+merge łączy gałęzie, zachowując pełną historię (tworzy merge commit). rebase przepisuje historię tak, jakby branch był stworzony z aktualnego HEAD — liniowa, czysta historia.
CI (Continuous Integration) — automatyczna weryfikacja kodu przy każdym push (build + testy). CD (Continuous Delivery/Deployment) — automatyczne wdrożenie do środowisk po przejściu CI.
Code review to nie polowanie na błędy — to dzielenie się wiedzą i podnoszenie jakości całego zespołu. Dobry review patrzy na czytelność, testy, bezpieczeństwo i zgodność z architekturą.
Gotowe! Sprawdź skrzynkę.
Za chwilę dostaniesz e-mail z dostępem do roadmapy. Jesteś też na liście VIP.
Nie widzisz wiadomości? Sprawdź folder Spam.
Zero spamu. Odblokowanie działa od razu, roadmapa wpada na maila.
Pytania to jedno. Umiejętności to drugie.
Pełny program Junior .NET Developer nauczy Cię nie tylko odpowiadać na pytania, ale przede wszystkim pisać kod, o który te pytania pytają. Zapisz się na listę VIP, aby wiedzieć o otwarciu zapisów.
Gotowe! Sprawdź skrzynkę.
Za chwilę dostaniesz e-mail z dostępem do roadmapy. Jesteś też na liście VIP.
Nie widzisz wiadomości? Sprawdź folder Spam.