Parę przykładów zagadek-kodowych w C#

Parę linijek kodu, proste pytanie co ten kod robi lub gdzie jest błąd. Nazywam to zagadkami. Czasem nawet  5 lat doświadczenie nie wystarczy aby odpowiedzieć prawidłowo na tego typu pytania. Poniżej lista paru zagadek, które zebrałem w jednym miejscu.

Osobiście zawsze gdy idę na rozmowę o pracę mam ze sobą swoją zagadkę, w razie gdybym nie odpowiedział na którąś zadaną mi przez rekrutera. Robię to po to aby pokazać, że zagadki nie mogą stanowić o tym, czy kto jest dobrym programistą, pokazują tylko czy kandydat odświeżył sobie wiedzę teoretyczną niedawno. Często na moją zagadkę rekruter nie odpowiada.

Zagadki

Z doświadczenia polecam uzbroić się w spory dystans do tego. Powodzenia!

  •  Zagadka 1:
public void Main()
{
    byte b = 1;
    dynamic d = b;
    Console.WriteLine(d.GetType());
    d += 1;
    Console.WriteLine(d.GetType());
}

Jaki typ będzie miała zmienna d? Kod ten jest prawidłowy i się kompiluje. Pierwsza instrukcja WriteLine wydrukuje oczywiście System.Byte. Jednak druga już pokaże System.Int32. Dlaczego?

Dzieje się tak, ponieważ gdyby nie słowo kluczowe dynamic, to operator „+” rzutuje zmienną d na Int32 i dodaje do niej 1. Następnie zmienił by ją spowrotem na System.Byte, jednak z powodu, że mamy słowo kluczowe dynamic ta powrotna konwersja już nie następuje.

Nie jestem dobry w używaniu dynamic wiec nie jestem w tym temacie biegły. Ale jak by się nad tym zastanowić działa to dość intuicyjnie.

Poniżej ten sam kod ale tym razem dodajemy zmienną byte do zmiennej byte:

public void Main()
{
    byte b = 1;
    byte byteVal = 1;
    dynamic d = b;
    Console.WriteLine(d.GetType());
    d += byteVal;
    Console.WriteLine(d.GetType());
}

Efekt jest ten sam. Znów widać, że operator „+” obsługuje Int32 po dodaniu tych wartości a słowo kluczowe dynamic skutecznie blokuje konwersję spowrotem.

  • Zagadka 2:

Czy poniższy kod rzuci wyjątkiem czy wydrukuje słowo „Działa!”?

public void Main()
{
  GetChars(null);
  Console.WriteLine("Działa!");
}

static IEnumerable<char> GetChars(string input)
{
    if (input == null)
        throw new ArgumentNullException(input);

    foreach (char c in input)
        yield return c;
}

Odpowiedź jest prosta. Metoda GetChars(null) nie wykona się dopóki nie będziemy przez nią iterować więc powyższy kod wydrukuje „Działa!”.

  • Zagadka 3:

Ta podobno jest prosta.

public void Main()
{
    var actions = new List<Action>();
	for(int i = 0; i < 5; i++)
        actions.Add(() => Console.WriteLine(i));
    foreach (var action in actions)
        action();
}

Co zostanie wydrukowane?  To proste jak się już wie : ) Będzie to pięć piątek. Ponieważ akcja WriteLine zostanie wykonana już po wykonaniu pętli for. Więc zmienna i będzie miała ustawioną wartość 5.

  • Zagadka 4:

Przedostatnia zagadka jest typem zagadki, które ewidentnie pokazują czy kandydat zrobił sobie głęboką powtórkę z teorii (i nie udowadnia niczego więcej)

public void Main()
{
	DoSomething(1);
}

void DoSomething(object x)
{
    Console.WriteLine("DoSomething(object x)");
}

void DoSomething<T>(params T[] x)
{
    Console.WriteLine("DoSomething<T>(params T[] x)");
}

Która metoda zostanie wykonana przez DoSomething(1)?

W następnym poście napisze dokładnie jak jest kolejność wyszukiwania odpowiedniego dopasowania. A teraz zgodnie ze specyfikacją C# lepszym dopasowaniem będzie parametr params T[] niż object.

  • Zagadka 5

Tę zagadkę często zadaje rekruterom na rozmowie.

public void Main()
{
    int a = 1;
    int? b = a == 1 ? null : 100;
}

Dlaczego ten kod się nie kompiluje?

Odpowiedz jest prosta. Operator trójargumentowy rzutuje wartość null na Int32 a nie na Int32? .

Robi tak, ponieważ typy danych, które ma zwrócić operator muszą być takie sama. W tym przypadku operator zwraca typ null lub 100 (czyli Int32). A powinny być Int32? i Int32?.

Poprawka do kodu, który się kompiluje wygląda tak:

public void Main()
{
    int a = 1;
    int? b = a == 1 ? (int?)null : 100;
}

lub tak:

public void Main()
{
    int a = 1;
    int? b = a == 1 ? null : (int?)100;
}

Podsumowanie:

Zagadki sprawdzają Naszą wiedzę teoretyczną i mogą jasno wskazać elementy do poprawy.

Jednak optymalny programista to programista z tą samą ilością wiedzy praktycznej jak i teoretycznej.  Gdy ktoś posiada wielką wiedzę teoretyczną (profesorowie akademicy) to mogą sobie nie poradzić tak dobrze w praktycznych sytuacjach.

„Wiedzieć co robi słowo kluczowe yield to jedno ale stosować go skutecznie to zupełnie co innego” – Przemysław Walkowski 

Więc polecam dbać o to by trzymać zawsze poziom wiedzy teoretycznej na tym samym poziomie co poziom wiedzy praktycznej.

11 przemyśleń nt. „Parę przykładów zagadek-kodowych w C#

  1. Bardzo dobry wpis kolego! Od dziś zacznę zwracać uwagę na takie zagadki. Wstyd się przyznać, ale połowy nie udało mi się rozwiązać.

  2. Niezły wpis. Zainspirowałeś mnie do zbierania takich kwiatków. Ogólnie podoba mi się idea zbijania takich pytań-zagadek.

    1. Super. Takie zagadki dobrze sprawdzaja miejsca gdzie brakuje teorii.

  3. W pierwszej zagadce mylisz się wyjaśniając takie działanie.

    byte b = 1;
    byte byteVal = 1;
    byte result = b + byteVal; // to się nie skompiluje, wynik jest int-em i dynamic na nic nie wpływa tutaj

    1. Nie skompiluje się, bo operator + nie ma takiego przeciążenia. Jednak już ten kod się skompiluje.
      byte b = 1;
      byte byteVal = 1;
      dynamic result = b + byteVal;
      Console.WriteLine(result.GetType());

      Na wyjściu będzie: System.Int32. Zgodnie z założeniami.

      1. No własnie i dlatego ta zagadka jest bez sensu :) Dynamic nic tutaj nie wnosi. To jest pytanie o to co zwraca operator +. Albo lepiej, czy istnieje operator +(byte, byte).

        „operator „+” rzutuje zmienną d na Int32 i dodaje do niej 1. Następnie zmienił by ją spowrotem na System.Byte, jednak z powodu, że mamy słowo kluczowe dynamic ta powrotna konwersja już nie następuje.”

        Operator niczego by nie zmienił. Zwraca int. To ewentualnie przypisanie mogłoby zmienić typ.

        1. Troche sie z Toba zgadzam. Zagadka jest pokretna i mozna powiedziec naciagana. Ale moze wlasnie o to w niej chodzi aby zobaczyc jak kandydat kombinuje. Dzieki za komentarze.

  4. Fajny wpis, dowiedziałem się czegoś nowego :D
    Szczerze odpowiedziałem poprawnie tylko na łatwy przykład którym jest zagadka 3. Swoją drogą fajnie że rekruterom zadajesz też zadanka. Myśle że jeżeli rekruter odmawia odpowiedzi to już źle o nim świadczy.

    1. Dzięki. Z rekruterami jest czasem tak, że maja gotowe pytania i poròwnują Twoją odpowiedz z tą, ktòra maja na kartce. Zero myślenia. Wiec czasem warto im pokazac z kim maja do czynienia ;)

Możliwość komentowania jest wyłączona.