Dacă știi un limbaj de programare C, cu siguranță nu vei duce lipsă de oportunități de angajare. Există numeroase companii care recruteaza activ programatori care cunosc limbajele C# sau C++, iar aceste posturi sunt vânate de mulți alți candidați, asemenea ție. Nu e motiv de panică, ci de acțiune!
Ca să ieși câștigător din procesul de recrutare, este esențial să te faci remarcat, iar interviul tehnic este unul dintre momentele cheie. Ți-am pregătit 50 de întrebări de interviu C# care acoperă aproape toate subiectele importante în termeni simpli, pentru a te ajuta să te pregătești cât mai bine pentru interviul cu angajatorul.
Dacă știi și alte limbaje de programare, cu atât mai bine! Ți-am pregătit 50 de întrebări de interviu Java cu care să-ți testezi cunoștințele.
Evită să memorezi o serie de răspunsuri standard și folosește ocazia pentru a susține cunoștințele listate în CV, completează noțiunile teoretice cu exemple din proiectele la care ai lucrat și pune în acțiune abilitățile de comunicare, astfel încă interviul să decurgă natural.
Acestea sunt sfaturile pe care mentorii Software Development Academy le oferă și absolvenților școlii, atunci când ajung în etapa de recrutare, pentru a obține jobul pe noi îl garantăm.
Iată 50 de întrebări frecvente într-un interviu de programator C# și răspunsurile care pot să te aducă un pas mai aproape de job-ul dorit.
Ești pregătit să începem?
C# este un limbaj de programare modern, cu scop general, este orientat pe obiecte și dezvoltat de către Microsoft. Se rulează pe .NET Framework. C# este foarte aproape, ca sintaxa, de limbajele de programare C/C++ și Java (cu mențiunea că este asemenea JAVA, un limbaj a cărui memorie este gestionată intern de către mecanismul de Garbage Collector, lucru care-l diferențiază de C++), și este folosit pentru crearea componentelor software.
CLR este componenta de bază și de Virtual Machine a .NET Framework. Este mediul din .NET Framework care rulează codurile și ajută la ușurarea procesului de dezvoltare prin accesul la diverse servicii, de exemplu – remoting, thread management, type-safety, memory management. Practic, este responsabil cu gestionarea execuției programelor .NET indiferent de limbajul de programare .NET.
Indexatorii sunt cunoscuți ca matrice inteligente în C# și permit ca instanțele unei clase să fie indexate în același mod ca o matrice.
Compilatorul Just-In-Time (JIT) este o parte a Common Language Runtime (CLR) în .NET, care este responsabil pentru gestionarea execuției programelor .NET, indiferent de limbajul de programare .NET. Un compilator specific limbajului convertește codul sursă în limbajul intermediar. Acest limbaj intermediar este apoi convertit în codul mașinii de către compilatorul Just-In-Time (JIT). Acest cod este specific mediului de computer pe care rulează compilatorul JIT.
Gestionarea automată a memoriei este posibilă prin Garbage Collection în .NET Framework. Când un obiect de clasă este creat în timpul rulării, un anumit spațiu de memorie îi este alocat în memoria heap. După ce toate acțiunile legate de obiect sunt finalizate în program, spațiul de memorie alocat acestuia este o risipă, deoarece nu poate fi utilizat. În acest caz, colectarea gunoiului este foarte utilă, deoarece eliberează automat spațiul de memorie.
Colectarea gunoiului va funcționa întotdeauna pe Managed Heap și, intern, are un motor cunoscut sub numele de Motor de optimizare. Colectarea gunoiului are loc dacă cel puțin una dintre mai multe condiții este îndeplinită:
Tipurile de clase în C# sunt:
Diferențele variază în funcție de versiunea de C# utilizată, iar acestea sunt:
În limbajul C#, conceptul metodei de extindere permite adăugarea de noi metode în clasa existentă sau în structură, fără a modifica codul sursă. Nu este nevoie de niciun fel de permisiune specială de la tipul original și nu este nevoie de recompilare.
Inheritance, sau moștenirea, este un pilon important al OOP (Object Oriented Programming). Este mecanismul în C# prin care unei clase i se permite să moștenească caracteristicile (câmpurile și metodele) unei alte clase.
Multiple inheritance nu este posibilă în limbajul de programare C#.
Managed code:
Unmanaged Code
O clasă este un model definit de utilizator sau un prototip din care sunt create obiecte. Practic, o clasă combină câmpurile și metodele (funcția membru care definește acțiunile) într-o singură unitate.
O structură este o colecție de variabile de diferite tipuri de date, sub o singură unitate. Este aproape similar cu o clasă, deoarece ambele sunt tipuri de date definite de utilizator și ambele dețin o mulțime de tipuri de date diferite.
Diferența majoră între cele doua tipuri este modul în care sunt salvate în memorie, clasele fiind “reference types”, adică accesate prin referinta sunt salvate în memoria heap, iar structurile sunt “value types” și sunt salvate pe stivă (stack), fiind accesate prin valoare.
Enumerarea reprezintă un tip de date de valoare în C#. Este folosit, în principal, pentru a atribui nume sau valori șirurilor constantelor integrale, ceea ce face un program ușor de citit și de întreținut.
De exemplu, cele 4 opțiuni dintr-un pachet de cărți de joc pot fi 4 enumeratori numiți Treflă, Romb, Cupa și Pică, aparținând unui tip enumerat numit Suită. Alte exemple includ tipuri naturale enumerate – cum ar fi planetele, zilele săptămânii, culorile, direcțiile etc.
Ref este un cuvânt cheie care este folosit în C# pentru transmiterea argumentelor printr-o referință. Sau putem spune că dacă orice modificări aduse acestui argument în metodă se vor reflecta în acea variabilă, atunci când controlul revine la metoda de apelare. Parametrul ref nu trece proprietatea.
Out este un cuvânt cheie în C# care este folosit pentru a transmite argumentele metodelor ca tip de referință. Este folosită, în general, atunci când o metodă returnează mai multe valori. Parametrul out nu trece proprietatea.
Boxul și unboxing-ul sunt concepte important în C#. Sistemul de tip C# conține trei tipuri de date: tipuri de valori (int, char, etc), tipuri de referință (obiect) și tipuri de indicator. Practic, convertește un tip de valoare într-un tip de referință și invers. Boxing și Unboxing permit o vizualizare unificată a sistemului de tipuri în care o valoare de orice tip poate fi tratată ca un obiect.
Boxing în C#
Unboxing în C#
Proprietățile sunt tipuri speciale de membri ai clasei care oferă un mecanism flexibil pentru a citi, scrie sau calcula valoarea unui câmp privat. Proprietățile pot fi folosite ca și cum ar fi membri de date publice, dar sunt de fapt metode speciale numite accessors. Acest lucru permite accesarea cu ușurință a datelor și ajută la promovarea flexibilității și siguranței metodelor.
Încapsularea și ascunderea informațiilor pot fi, de asemenea, realizate folosind proprietăți. Folosește metode predefinite, care sunt metodele „get” și „set”, care ajută la accesarea și modificarea proprietăților.
O astfel de clasă oferă o capacitate specială de a implementa funcționalitatea unei singure clase în mai multe fișiere și toate aceste fișiere sunt combinate într-un singur fișier de clasă atunci când aplicația este compilată.
O clasă parțială este creată folosind un cuvânt cheie parțial. Acest cuvânt cheie este, de asemenea, util pentru a împărți funcționalitatea metodelor, interfețelor sau structurii în mai multe fișiere.
public partial Class_name
{
// Code
}
Când un obiect este atribuit unei variabile obiect de tipul specific, atunci compilatorul C# realizează legarea cu ajutorul .NET Framework. C# realizează două tipuri diferite de legături care sunt:
Early Binding recunoaște și verifică metodele sau proprietățile în timpul compilării. În această legare, compilatorul știe deja ce fel de obiect este și care sunt metodele sau proprietățile pe care le deține, aici obiectele sunt statice. Performanța early binding este rapidă și este ușor de codificat. Reduce numărul de erori de rulare.
În Late Binding, compilatorul nu știe ce fel de obiect este și care sunt metodele sau proprietățile pe care le deține, aici obiectele sunt dinamice. Tipul obiectului este decis pe baza datelor pe care le deține în partea dreaptă în timpul rulării. Practic, legarea tardivă se realizează prin utilizarea metodelor virtuale. Performanța este mai lentă decât a legării timpurii, deoarece necesită căutări în timpul execuției.
Method Overloading este modalitatea comună de implementare a polimorfismului. Este capacitatea de a redefini o funcție în mai multe forme. Un utilizator poate implementa supraîncărcarea funcțiilor prin definirea a două sau mai multe funcții într-o clasă care are același nume.
C# poate distinge metodele cu semnături diferite de metode, adică metodele pot avea același nume, dar cu o listă de parametri diferiți (adică numărul parametrilor, ordinea parametrilor și tipurile de date ale parametrilor) în cadrul aceleiași clase.
Reflection este procesul de descriere a metadatelor tipurilor, metodelor și câmpurilor dintr-un cod. Spațiul dSystem. Reflection permite obținerea de date despre ansamblurile încărcate, elementele din ele, cum ar fi clase, metode și tipuri de valori.
În limbajul C#, un cuvânt cheie constant este folosit pentru a declara câmpuri și locale constante. Valoarea câmpului constant este aceeași pe tot parcursul programului sau, cu alte cuvinte, odată ce câmpul constant este atribuit, valoarea acestui câmp nu se modifică.
În C#, câmpurile constante și localurile nu sunt variabile, o constantă este un număr, șir, referință nulă, valori booleene. Cuvântul cheie read-only este folosit pentru a declara o astfel de variabilă. Acest cuvânt cheie arată că se poate atribui variabila numai atunci când declari o variabilă, sau într-un constructor din aceeași clasă în care este declarată.
Jagged Arrays reprezintă o matrice de matrice ale cărei elemente sunt matrice de dimensiuni diferite. Cu alte cuvinte, lungimea fiecărui index de matrice poate diferi. Elementele din Jagged Array sunt tipuri de referință și inițializate implicit la nul. Jagged Array poate fi, de asemenea, amestecat cu matrice multidimensionale. Aici, numărul de rânduri va fi fixat la momentul declarației, dar poți varia numărul de coloane.
În C#, StringBuilder este similar cu Java StringBuilder. Un obiect String este imuabil, adică nu poate fi schimbat odată creat. De fiecare dată când utilizezi oricare dintre metodele clasei System.String, un nou obiect string este creat în memorie.
De exemplu, un șir SDA Romania” ocupă memorie în heap, acum, schimbarea șirului inițial în „CR” va crea un nou obiect șir în heap-ul de memorie, în loc să modifice șirul inițial în aceeași locație de memorie. În situațiile în care trebuie să efectuezi modificări repetate la un șir, ai nevoie de clasa StringBuilder. Pentru a evita înlocuirea, adăugarea, eliminarea sau inserarea șirurilor de caractere noi în șirul inițial C# este introdus conceptul StringBuilder. StringBuilder este un obiect dinamic. Nu creează un obiect nou în memorie, ci extinde în mod dinamic memoria necesară pentru a găzdui șirul modificat sau nou.
Tehnica System.Array.CopyTo() face o replică a componentelor într-o altă matrice existentă. Face copii ale componentelor unui cluster într-o altă matrice existentă.
Tehnica Clone() returnează un nou obiect matrice care conține fiecare dintre componentele din prima matrice. Clone() face o duplicare a unui matrice, care este de tip similar cu prima matrice.
Diferența principală dintre aceste metode este că dispose() trebuie invocată în mod explicit de către utilizator, iar finalize() este apelată de colectorul de gunoi atunci când obiectul este distrus.
Un delegat este o variabilă care poate conține o referință la metode. Delegații în C# sunt similari cu indicatorul de funcție din C/C++. Oferă o modalitate care spune ce metodă trebuie apelată atunci când este declanșat un eveniment. De exemplu, atunci când dai click pe un buton dintr-un formular, programul va apela o anumită metodă. Un delegat reprezintă referințe la metode, cu o anumită listă de parametri și un tip de returnare, și apoi apelează metoda într-un program pentru execuție, atunci când este necesar.
Clasele sigilate sunt folosite pentru a restricționa utilizatorii să moștenească clasa. O clasă poate fi sigilată utilizând cuvântul cheie sealed. Cuvântul cheie îi spune compilatorului că respectiva clasa este sigilată și, prin urmare, nu poate fi extinsă. Nicio clasă nu poate fi derivată dintr-o clasă sigilată.
Următoarea este sintaxa unei clase sigilate:
sealed class class_name
{
// data members
// methods
.
.
.
}
Poți apela un constructor supraîncărcat de la un alt constructor folosind acest cuvânt cheie, dar constructorul trebuie să aparțină aceleiași clase, deoarece acest cuvânt cheie indică către membrii aceleiași clase în care este utilizat. Acest tip de apelare a constructorului supraîncărcat este denumit și Constructor Chaining.
Multicasting-ul delegatului este o extensie a delegatului obișnuit, uneori numit și delegat de distribuție unică. Ajută utilizatorul să indice mai mult de o metodă într-un singur apel.
Generic este o clasă care permite utilizatorului să definească clase și metode cu substituent. Genericele au fost adăugate la versiunea 2.0 a limbajului C#. Ideea de bază din spatele utilizării generice este de a permite tipului (întreg, șir, etc. și tipuri definite de utilizator) să fie un parametru pentru metode, clase și interfețe.
O limitare principală a colecțiilor este absența unei verificări eficiente de tip. Aceasta înseamnă că poți pune orice obiect într-o colecție, deoarece toate clasele din limbajul de programare C# se extind din clasa de bază a obiectului. Acest lucru compromite siguranța tipului și contrazice definiția de bază a C# ca limbaj de tip sigur.
Există 4 modificatori de acces (public, protejat, intern, privat) care definesc cele 6 niveluri de accesibilitate, după cum urmează:
În C#, Virtual Method este o strategie care poate fi reclasificată în clase derivate. Poți implementa metoda virtuală în clasa de bază și clasa derivată. Este utilizat atunci când activitatea fundamentală a unei metode este similară, dar în unele cazuri clasa derivată a avut nevoie de funcționalități suplimentare. O metodă virtuală este declarată în clasa părinte care poate fi suprascrisă în clasa copil.
Facem o metodă virtuală în clasa de bază folosind cuvântul cheie Virtual și acea metodă este suprascrisă în clasa derivată folosind cuvântul cheie Override. Nu este necesar ca fiecare clasă derivată să moștenească o metodă virtuală, dar o metodă virtuală trebuie creată în clasa de bază. Prin urmare, metoda virtuală este cunoscută și ca polimorfism.
Multi-threading este un proces care conține mai multe fire de execuție (threaduri) într-un singur proces. Aici fiecare thread desfășoară activități diferite. De exemplu, avem o clasă și acest apel conține două metode diferite, acum folosind multithreading fiecare metodă este executată de un thread separat.
Deci, avantajul major al multithreading-ului este că funcționează simultan, ceea ce înseamnă că se execută mai multe sarcini în același timp. Și, de asemenea, maximizarea utilizării procesorului, deoarece multithreading funcționează pe conceptul de partajare a timpului, însemnând că fiecare fir își ia propriul timp pentru execuție și nu afectează execuția unui alt thread, acest interval de timp este dat de sistemul de operare.
Clasa Hashtable reprezintă o colecție de perechi cheie/valoari care sunt organizate pe baza codului hash al cheii. Această clasă face parte din System. Collections și oferă diferite tipuri de metode care sunt utilizate pentru a efectua diferite tipuri de operații pe hashtables. În Hashtable, cheile sunt folosite pentru a accesa elementele prezente în colecție. Pentru obiectele Hashtable foarte mari, se poate crește capacitatea maximă la 2 miliarde de elemente pe un sistem pe 64 de biți.
Deoarece metodele virtuale private nu sunt accesibile în afara clasei. Cuvântul cheie virtual este utilizat tocmai în ideea de a evidenția faptul că respectiva metodă poate fi suprascrisă în clasa copil, atâta timp cât metoda este privată ea nu este vizibilă în afara clasei și, prin urmare, nu poate fi accesată de clasa copil.
În general, fișierul este folosit pentru a stoca datele. Termenul de manipulare a fișierelor se referă la diferite operațiuni cum ar fi crearea fișierului, citirea, scrierea, adăugarea, etc. Există două operațiuni de bază care sunt utilizate cel mai mult în manipularea fișierului iar acestea sunt citirea și scrierea. Din fișier se pot forma două fluxuri, unul este fluxul de intrare care este utilizat pentru a citi fișierul și altul este fluxul de ieșire este folosit pentru a scrie în fișier. În C#, spațiul de nume System.IO conține clase care se ocupă de fluxurile de intrare și de ieșire și oferă informații despre structura fișierelor și directoarelor.
O excepție este o eroare care apare în timpul execuției. Folosind subsistemul de gestionare a excepțiilor C#, putem, într-o manieră structurată și controlată, să gestionăm erorile de rulare. Avantajul principal al gestionării excepțiilor este că automatizează o mare parte din codul de gestionare a erorilor. O gestionare a excepțiilor este, în plus, importantă deoarece C# definește excepții standard pentru erorile comune ale programului, cum ar fi împărțirea la zero sau indexarea în afara intervalului.
Excepțiile C# cu semnificația lor:
C# include trei cuvinte cheie care acceptă identificarea tipului de rulare: is, as, și typeof.
Operator is: se poate determina dacă un obiect este de un anumit tip utilizând operatorul is. Forma sa generală este:
expr is type
Aici, expr este o expresie care descrie un obiect al cărui tip este testat împotriva type. Dacă tipul de expr este același sau compatibil cu type, atunci rezultatul acestei operații este adevărat.
Altfel, este fals. Astfel, dacă rezultatul este adevărat, expr este o formă de tip. Deoarece se aplică la is, un tip este compatibil cu altul dacă ambele sunt echivalente cu tipul sau dacă există o conversie de referință, boxing sau unboxing.
Operator as: Uneori, dacă vrem să încercăm o conversie în timpul execuției, dar nu să aruncăm o excepție dacă conversia eșuează (ceea ce este cazul când se folosește un cast). Pentru a face acest lucru, se utilizează operatorul as, care are această formă generală:
expr as type
Aici, expr este expresia care este convertită în tip. Dacă conversia reușește, atunci este returnată o referință la tip. În caz contrar, este returnată o referință nulă. Operatorul as poate fi folosit pentru a efectua doar conversii de referință, boxing, unboxing sau identitate.
Modelul de design singleton în C# este unul comun. În acest model, o clasă are doar o singură instanță în program care oferă acces global la aceasta. Sau, se poate spune că Singleton este o clasă care permite realizarea unei singure instanțe, și de obicei oferă acces simplu la acea instanță.
Există diferite abordări pentru a realiza un design Singleton în C#. Iată care sunt atributele obișnuite ale unui design Singleton:
Putem implementa un model de design Singleton în C# folosind:
Cuvântul tuple înseamnă „o structură de date care constă din mai multe părți”. Deci este o structură de date care oferă cea mai simplă modalitate de a reprezenta un set de date care are mai multe valori care pot/s-ar putea să nu fie legate între ele. A fost introdus în .NET Framework 4.0. În tuple, se pot adăuga elemente de la 1 la 8. Dacă încerci să adăugați elemente mai mari de opt, atunci compilatorul va arunca o eroare. Tuplurile sunt utilizate, în general, atunci când se dorește crearea unei structuri de date care conține obiecte cu proprietățile lor și nu se dorește crearea un tip separat pentru asta.
Un events, sau eveniment, este o notificare automată că a avut loc o acțiune. Delegații și evenimentele sunt legate deoarece un eveniment este construit pe un delegat. Ambele extind setul de sarcini de programare la care se poate aplica C#.
Evenimentele funcționează astfel – un obiect care are un interes într-un eveniment înregistrează un handler de evenimente pentru acel event. Când are loc, sunt apelați toți handlerii înregistrați. Managerii de evenimente sunt reprezentați de delegați.
Events sunt membri ai unei clase și sunt declarate folosind cuvântul cheie event.
Forma sa cea mai des folosită este aceasta:
event event-delegate event-name;
Aici, event-delegate este numele delegatului folosit pentru a susține evenimentul, iar event-name este numele obiectului eveniment specific care este declarat.
Principala diferență este că metoda Dispose() este folosită pentru a elibera resursele negestionate ale unui obiect, în timp ce Finalize() este, de asemenea, utilizat în același scop, dar nu garantează colectarea gunoiului unui obiect. O altă diferență majoră este că metoda dispose() este invocată în mod explicit de către utilizator, iar metoda finalize() este invocată de colectorul de gunoi, chiar înainte ca obiectul să fie distrus.
Array este un grup de variabile similare la care se face referire printr-un nume comun. ArrayList reprezintă o colecție ordonată a unui obiect, care poate fi indexată individual. Este incorect să definim ArrayList este o colecție de obiecte. Conform documentației Microsoft, este de evitat utilizarea tipului ArrayList (link aici – secțiunea remarci aka Remarks), de preferat ar fi să apelăm la utilizarea tipurilor generice: List<Object>.
SortedList o colecție de perechi cheie/valoari care sunt sortate în funcție de chei. În mod implicit, această colecție sortează perechile cheie sau vaorile în ordine crescătoare. Este atât de tip generic, cât și de colecție negeneric.
SortedDictionary o colecție generică care este folosită pentru a stoca perechile cheie/valoarile în forma sortată, iar sortarea se face pe cheie.
Acestea oferă o modalitate de a păstra un set de nume (cum ar fi numele claselor) diferit de alte seturi de nume. Cel mai mare avantaj al utilizării namespace este că numele de clasă care sunt declarate într-un spațiu de nume nu se vor ciocni cu aceleași nume de clasă declarate într-un alt spațiu de nume.
Membrii pot fi spații de nume, interfețe, structuri și delegați.
Cele patru concepte fundamentale ale programării orientate pe obiecte sunt:
Când două fire accesează aceeași resursă și încearcă să o schimbe în același timp, apare această condiție de cursă. Este aproape imposibil de prezis care fir reușește să acceseze mai întâi resursa. Iar când două fire încearcă să scrie o valoare în aceeași resursă, ultima valoare scrisă este cea salvată.
În prezent, SDA îți oferă câteva cursuri cu ajutorul cărora poți face primii pași în programare, în domeniul Front-end sau Back-end: cursuri de Python, Java și Javascript.
În afară de cursurile în sine, SDA oferă un pachet generos de sprijin în carieră care include:
Pe toată durata cursurilor, vei fi ghidat de mentorii noștri care te inspiră chiar și online și care te vor motiva să reușești. Programarea poate fi învățată în multe moduri, dar noi la SDA suntem de părere că puterea exemplului este cea mai bună metodă.
În plus, ce face diferența dintre un programator bun și unul excelent sunt soft skill-urile, așa că la SDA le-am inclus obligatoriu în programă. În cadrul fiecărui modul vei avea ședințe special dedicate dezvoltării și deprinderii celor mai importante soft skill-uri pentru a învăța să abordezi corect și eficient orice task și a căpăta încredere de sine.
Cele două școli și-au unit forțele! Împreună, oferim:
Înscrie-te acum în programul SDAcademy x Codecool și primește coaching personalizat pentru cariera ta în IT!