niedziela, 15 marca 2009

[C2C 2009] Rozwiązanie konkursu kartkowego

Konferencja C2C 2009 dobiegła końca, zdobyliśmy trochę wiedzy i poznaliśmy nowych ludzi. Zostały miłe wspomnienia i odliczanie do C2C 2010. Zanim przejdę do rozwiązań konkursu "kartkowego", chciałbym podziękować jeszcze raz wszystkim uczestnikom za przybycie (ze wszystkich zarejestrowanych na ścieżkę .NET nie stawiły się mniej więcej tylko 2 osoby!), sponsorom za wsparcie i pozostałym organizatorom za poświęcenie swojego czasu dla stworzenia tak wspaniałego wydarzenia (szczególnie tym najbardziej zasłużonym – będą wiedzieć którzy to :) ).

Konkurs jak przypomnę składał się z 5 pytań i miał naturę "haczykowatą" oraz miał za zadanie być jak najtrudniejszy. Jak wyszło oraz czy zadania były fajne, okaże się w komentarzach :]

Zadanie 1

class A
{
protected int i = 2;
}

class B : A
{
private int i;

public B() {
i = 2009;
}
}

class C : B
{
public int GetNumber()
{
return i;
}
}
Wywołanie:
C c = new C();
int result = c.GetNumber();
Jaki będzie wynik wykonania programu:
1. Zmienna „result” będzie równa 2,
2. Zmienna „result” będzie równa 2009,
3. Zmienna „result” będzie równa 0,
4. Kod się nie skompiluje,
5. Wystąpi błąd w czasie działania aplikacji.

Prawidłowa odpowiedź to oczywiście 1.

Podczas inicjalizacji konstruktora w klasie B, "i" zmieni się tylko lokalnie, ponieważ jest private. W klasie C, zmienna "i" będzie pobrana z klasy A, gdzie wynosi 2.

Zadanie 2

       byte a = 10;
byte b = 01;
byte c = a + b;
Jaki będzie wynik wykonania programu:
1. Zmienna „c” będzie zawierać liczbę 1001,
2. Zmienna „c” będzie zawierać liczbę 11,
3. Zmienna „c” będzie zawierać liczbę 3,
4. Kod się nie skompiluje,
5. Wystąpi błąd w czasie działania aplikacji.

Prawidłowa odpowiedź to 4.

Kod się nie skompiluje, ponieważ domyślnym typem wartości z dodawania jest integer (int), a przypisanie byte c = integer; - bez rzutowania, rozpoznawane jest jako błąd (integer może nie zmieścić się w byte i mogą zostać utracone dane).

Zadanie 3

class A
{
public A(int number)
{
number = number;
}
public int number = 2;
}

class B : A
{
public B(int number)
{
number = new A(number).number;
}
}

class C : B
{
public C(int number)
: base(number)
{

}
}
Wywołanie:
C c = new C(2009);
int result = c.number;
Jaki będzie wynik wykonania programu:
1. Zmienna „result” będzie zawierać liczbę 2,
2. Zmienna „result” będzie zawierać liczbę 2009,
3. Zmienna „result” będzie zawierać liczbę 0,
4. Kod się nie skompiluje,
5. Wystąpi błąd w czasie działania aplikacji.

Prawidłowa odpowiedź to 4.

To zadanie polegało na wykryciu braku konstruktora bezparametrowego w klasie A. Jak zapewne każdy z nas wie, gdy w klasie istnieje jakikolwiek inny konstruktor, to kompilator nie generuje tego domyślnego bez parametru. W tym zadaniu w klasie B, poszukiwany jest domyślny bezparametrowy konstruktor z klasy A, który nie istnieje i kod w związku z tym się nie kompiluje.

Zadanie 4

Dana jest następująca tablica:
string[] imiona = { "Adam", "Ala", "Michał" };
Który fragment kodu poprawnie wyświetli imiona na konsoli?
1. foreach (var imie in imiona.Where(imie => imie.IndexOfAny(new char[] { 'a' }) > 0)) {
Console.WriteLine(imie ?? String.Empty.ToString()); }
2. foreach (int imie in imiona.SingleOrDefault(imiona => imiona.Length)) {Console.WriteLine(imiona[i]);}
3. Array.ForEach((from imie in imiona select imie.ToString()), imie => Console.WriteLine(imie));
4. foreach (string imie in imiona) { Console.WriteLine(imiona[imie.IndexOf(0)]); }
5. foreach (string imie in imiona) { Console.WriteLine(imiona); }

Prawidłowa odpowiedź to 1.

Trochę LINQu pomieszane z czym się dało. Szacunek dla tych którzy potrafili przeanalizować ten kod. :]

Zadanie 5

class Parent
{
static Parent()
{
_message = "Hello!";
}

static public string Message
{
get { return _message; }
}

static protected string _message;
}

class Child : Parent
{
static Child()
{
_message = "Hello, World!";
}
}
Wywołanie:
Console.WriteLine(Child.Message);
new Child();
Console.WriteLine(Child.Message);
Jaki będzie wynik wykonania programu:
1. Na konsole zostaną wypisane znaki: "Hello!", "Hello!",
2. Na konsole zostaną wypisane znaki: "Hello!", "Hello, World!",
3. Na konsole zostaną wypisane znaki: "Hello, World!", "Hello, World!",
4. Na konsole zostaną wypisane znaki: "Hello, World!", "Hello!",
5. Kod się nie skompiluje.

Prawidłowa odpowiedź to 2.

Ostatnie zadanie i chyba najtrudniejsze ze wszystkich, wymagało bardzo dobrej znajomości kompilatora C#. Niektórzy nazywają to zachowanie Bugiem kompilatora. Wartość _message nie zostanie ustawiona dopóki nie było pierwszego odwołania do konstruktora Child. Pierwsze odwołanie new Child() ustawia nową wartość zmiennej _message. Stąd też najpierw tekst "Hello!" a później "Hello, World!".

Podsumowanie

Dziękuje wszystkim którzy wzięli udział w konkursie, mam nadzieje że podobał się Wam i gratuluje wygranych!


Pozdrawia,

Jacek Ciereszko

3 komentarze:

Andrzej Piotrowski pisze...

Wiesz Tomku , pomysł super ale zapomniałeś że nie którzy mieli laptopy oraz kompilowali to co dawałeś :) Wiadomo , nie idze każdemu dogodzić ale następnym razem może coś z algorytmów ;P

Ja powiem że pomagałem komuś bo wiedza w grupie sprawdza sie lepiej.
I tak na logikę niż znając architektura wpadłem na niby najcięższe pytanie nr 5 ;)
Po prostu jest sobie Parent i Child , Napierw Parent potem Child :P

Jacek pisze...

No tak, laptopy były zdecydowanie minusem tego konkursu ale ciężko by było je wyeliminować. Algorytmy natomiast mogły by być pewnym rozwiązaniem ale utrudniło by to sprawdzanie.

Kto chciał to pomęczył się z zadaniami i liczę że dobrze bawił. :) Na przyszłość pomyśli się nad takimi kawałkami kodu aby czas wymagany do przeklepania zadań był zbyt długi. :P

p.s. a ja to Jacek jestem, chyba że to nie do mnie był komentarz ;]

Anonimowy pisze...

Przepisanie kodu to raz, a dwa powinien byc okreslony czas na konkurs,
powiedzmy jest duzo kodu a dwa odpowiedzi trzeba oddac po pierwszej czy tam drugiej sesji :)