Blog Dla Młodszych Programistów C#/.NET

W poprzednich wpisach przedstawiłem Ci już 40 popularnych pytań, z którymi możesz się spotkać na rozmowie kwalifikacyjnej o pracy na stanowisku młodszego programisty C#. Najwyższa pora przejść do kolejnych. Dzisiaj znowu przedstawię Ci 10 kolejnych pytań wraz z odpowiedziami.

100 Pytań (i Odpowiedzi!) z Rozmów Kwalifikacyjnych Dla Młodszych Programistów C#/.NET (Część 5/10)


41) Jaka jest różnica pomiędzy IList, a List? Jakie mają zastosowanie?


Przede wszystkim IList jest interfejsem, a List jest klasą. List jest konkretną implementacją IList. Zazwyczaj, jeżeli udostępniamy swoją klasę za pośrednictwem biblioteki, z której będą korzystać inni, to lepiej udostępnić ją za pomocą intefejsu, a nie już konkretnej implementacji. Takie rozwiązanie jest bardziej rozszerzalne, uniwersalne.

Pozwoli to w przyszłości zabezpieczyć się przed ewentualnymi zmianami. Jeżeli w przyszłości zmienisz klasę List na inną, to użytkownicy, którzy implementują Twoją bibliotekę, będą musieli dokonać wielu zmian, a w przypadku gdy użyjesz IList, to taka zmiana nie będzie konieczna.

private static IList<int> _listInterface;
private static List<int> _listClass;


42) Jaka jest różnica pomiędzy interfejsem, a klasą abstrakcyjną w C#?


Najważniejsze różnice:
-W deklaracji interfejsu używamy słowa kluczowego interface, a w klasie abstrakcyjnej abstract class.
-Klasa może implementować dowolną ilość interfejsów, a dziedziczyć może tylko po 1 klasie abstrakcyjnej.
-Składowe interfejsu nie mogą zostać oznaczone atrybutami dostępu (domyślnie ustawiony jest public), a w klasie abstrakcyjnej mogą zostać oznaczone atrybuty dostępu.
-W interfejsie nie można deklarować pól, a w klasie abstrakcyjnej można to robić.
-Interfejs nie może mieć konstruktora, a w klasie abstrakcyjnej może być implementacja konstruktora domyślnego.

Co do przypadków użycia, to warto używać klasy abstrakcyjnych i dziedziczenia, jeżeli możesz sformułować stwierdzenie "A to B". Natomiast interfejsów używaj, jeśli możesz sformułować stwierdzenie "A jest wstanie robić B".

public abstract class Shape
{
}

public interface IPaintable
{
}


43) Czym jest konstruktor kopiujący?


Konstruktor kopiujący jest to konstruktor, który jako parametr przyjmuje instancje swojej klasy i kopiuje wartości pól tego obiektu. Czyli nie jest kopiowana referencja, tylko wartości pól.

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Student(Student student)
    {
        Id = student.Id;
        Name = student.Name;
    }
}


44) Czym są metody rozszerzone w C#?


Dzięki metodom rozszerzającym możemy rozszerzyć funkcjonalność typów już istniejących, np. takich, do których definicji nie mamy dostępu. Dobrym przykładem takich metod mogą być metody LINQ, gdzie korzystamy właśnie z metody rozszerzających, między innymi Sum(), Min(), Max(), Take() itd., to są wszystko metody rozszerzające IEnumerable.

Metoda rozszerzająca musi być statyczna oraz zostać zadeklarowana w klasie statycznej i przed pierwszym parametrem musi zawierać słowo kluczowe this przed typem, który chcemy rozszerzyć.

public static class StringExtensions
{
     public static void Display(this string value)
     {
         Console.WriteLine(value);
     }
}
public class Program
{   
    static void Main(string[] args)
    {
         var title = "Programowanie w C#";
         title.Display();//Programowanie w C#
    }
}


45) Jaka jest różnica pomiędzy throw, a throw exception w bloku catch?


W zapisie throw nie tracimy informacji zawartej w stack trace (stos wywołań). Także, jeżeli skorzystamy z throw exception, to w takim przypadku nie dostaniemy pełnej informacji o wszystkich wcześniej rzuconych wyjątkach w tym stosie. Czyli nie będziemy mieli pełnej informacji o błędach, które wystąpiły w naszej aplikacji, przez co jego zdiagnozowanie będzie trudniejsze.

Podsumowując, lepszą praktyką jest pierwszy scenariusz, czyli samo throw.

try
{
}
catch (Exception exception)
{
    throw;
}

try
{
}
catch (Exception exception)
{
    throw exception;
}


46) Jaka jest różnica pomiędzy string, a StringBuilder?


Główna różnica jest taka, że string jest tzw. obiektem immutable, czyli niezmiennym, z kolei StringBuilder jest mutable, czy zmiennym. To znaczy, StringBuilder wprowadza zmiany w istniejącym obiekcie, a nie tworzy za każdym razem nowego obiektu. W związku z kolei, że string jest niezmiennym, to jest to klasa mniej wydajna, ponieważ za każdym razem tworzy zupełnie nowy obiekt.

Jeżeli potrzebujesz stworzyć tekst, który nie będzie się zmieniał, to możesz jak najbardziej użyć stringa, a w przeciwnym przypadku lepiej użyć StringBuilder’a.

var simpleString = string.Empty;

for (int i = 0; i < 1000; i++)
{
    simpleString += i.ToString() + " ";
}

Tutaj zostanie stworzonych 1000 obiektów, z czego 999 nie będzie używanych.

var simpleStringBuilder = new StringBuilder();

for (int i = 0; i < 1000; i++)
{
    simpleStringBuilder.Append($"{i} ");
}


47) Jaka jest różnica pomiędzy słowami kluczowymi "is" oraz "as" w C#?


Operator is służy do sprawdzenie zgodności obiektu z danym typem i zwraca boola.

Z kolei operator as służy do rzutowania obiektu na dany typ.

if (student is Person)
    (student as Person).DisplayName();


48) Jaka jest różnica pomiędzy typem wartościowym, a referencyjnym?


Typ wartościowy to elementy, które rozszerzają System.ValueType i są to typy wartościowe takie jak na przykład int, long, double, decimal, bool. Przechowywane są one na stosie. Przy przypisywaniu zmieniana jest tylko sama wartość.

Typ referencyjny są to elementy dziedziczące po klasie System.Object oraz System.String, czyli głównie klasy, tablice, listy, stringi. Referencja do pamięci umieszczana jest na stosie, ale obszar pamięci, do jakiego prowadzi referencja, znajduje się na stercie. Są usuwane z pamięci za pomocą Garbage Collectora. Przy przypisaniu następuje tak naprawdę skopiowana referencja, a nie sama wartości, jak to ma miejsce w typach wartościowych. Po takiej operacji oba obiekty będą wskazywać na takie samo miejsce w pamięci.


49) Czym jest interfejs IDisposable?


Podstawowym zastosowaniem interfejsu IDisposable jest zwolnienie niezarządzanych zasobów. Garbage Collector automatycznie zwalnia pamięć zarządzaną, jeżeli obiekty nie są dłużej używane. Jednak nie można przewidzieć, kiedy to nastąpi.

Ponadto Garbage Collector nie ma wiedzy o niezarządzanych zasobach, takich jak pliki czy strumienie. Klasa implementująca interfejs IDisposable musi zaimplementować metodę Dispose, w które może zwolnić te zasoby. Jeżeli chcemy przekazać obiekt do bloku using, to właśnie musi on implementować ten interfejs.

public class Student : IDisposable
{
    public void Dispose()
    {
        //zwalnianie zasobow, plikow, strumieni itp
    }
}


50) Czym są operacje synchroniczne i asynchroniczne?


Programowanie asynchroniczne pozwala odciążyć pracę. Możemy wykonać dane zadania bez blokowania głównego wątku.

W operacjach synchronicznych zadania są wykonywane pojedynczo i dopiero po ich zakończeniu następuje odblokowanie następnych. Czyli zawsze trzeba poczekać na zakończenie zadania, aby móc przejść do kolejnego.

Jeżeli chodzi o operacje asynchroniczne, to tutaj możesz przejść do innego zadania przed zakończeniem poprzedniego. Dzięki temu w programowaniu asynchronicznym możemy obsłużyć wiele żądań jednocześnie, a co za tym idzie wykonać więcej zadań w krótszym czasie.

W C#, aby napisać metodę asynchroniczną, należy w sygnaturze użyć słowa kluczowego async, zwracać Taska, a wykonywane zadanie, które jest wykonywane wewnątrz metody i wymaga więcej czasu na wykonanie, oznaczyć słowem await.

public async Task<string> GetResult()
{
    return await Result();
}


ZAKOŃCZENIE


To tyle pytań w tym artykule. Kolejne przeanalizujemy już w przyszłym materiale. Jeżeli taki materiał Ci się spodobał, to koniecznie dołącz do mojej społeczności – darmowe zapisy, gdzie będziesz również miał dostęp do dodatkowych materiałów.

To wszystko na dzisiaj, do zobaczenia w kolejnym artykule.

Poprzedni artykuł - 100 Pytań (i Odpowiedzi!) z Rozmów Kwalifikacyjnych Dla Młodszych Programistów C#/.NET (Część 4/10).
Następny artykuł - 100 Pytań (i Odpowiedzi!) z Rozmów Kwalifikacyjnych Dla Młodszych Programistów C#/.NET (Część 6/10).
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
Programista C#/.NET. Specjalizuje się w ASP.NET Core, ASP.NET MVC, ASP.NET Web API, Blazor, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Komentarze (6)
Pawe
PAWE, 5 stycznia 2022 21:01
Jaka jest różnica pomiędzy interfejsem, a klasą abstrakcyjną w C# Interfejs nie może posiadać implementacji metod a jedynie ich deklaracje. Fakt uległo to zmianie w .NET 5 ale wciąż warto to zaznaczyć. Dodatkowo aby użyć tej metody trzeba stworzyć obiekt o typie interfejsu IFoo foo = new Foo(); Czym są metody rozszerzone w C#? Jeszcze nigdy nie spotkałem się z polskim sformułowaniem ;) Przyznam, że w pierwszej myśli nie załapałem, że chodzi o extensions methods Przy try catch brakuje mi wspomnienia o final ;)
Abs
ABS, 23 sierpnia 2022 10:47
Dobrze by było też podawać angielskie odpowiedniki nazw (np. extension methods)
Ela
ELA, 17 grudnia 2022 21:28
Tutaj tez mam wątpliwości co do tego stwierdzenia: "W interfejsie nie można deklarować pól, a w klasie abstrakcyjnej można to robić." Chyba chodziło o inicjalizowanie pól a nie o ich deklarowanie, bo deklarować pola w interfejsie można... public interface IPaintable { string SimpleStr { get; set; } }
Kazimierz Szpin
KAZIMIERZ SZPIN, 20 grudnia 2022 07:45
@ELA, w interfejsie nie można deklarować pól, to się zgadza. To co podałaś jako przykład, to właściwość (properties), a właściwości można deklarować jak najbardziej :)
Kazimierz Szpin
KAZIMIERZ SZPIN, 20 grudnia 2022 07:48
@PAWE, masz rację z .NET 5. Każdą z tych odpowiedzi pewnie można jeszcze rozwinąć, starałem się odpowiadać w miarę krótko i konkretnie :)
Kazimierz Szpin
KAZIMIERZ SZPIN, 20 grudnia 2022 07:50
@ABS, racja, warto o tym wspomnieć :)
Dodaj komentarz

Wyszukiwarka

© Copyright 2024 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin