← Wszystkie wpisy

Błąd CS0029: co dokładnie mówi kompilator

Kompilator nie odmawia dlatego, że kod jest zły. Ten komunikat znaczy, że między dwoma typami nie ma żadnej drogi, a nie że brakuje rzutowania.

Artur Kot 5 min czytania

CS0029 znaczy, że między typem, który podałeś, a typem, którego oczekuje zmienna, nie istnieje żadna konwersja. Nie brakuje rzutowania. Kompilator nie zna sposobu zamiany jednego typu na drugi i nie zamierza go wymyślać za Ciebie.

Pełny komunikat z prawdziwej kompilacji wygląda tak:

Program.cs(2,12): error CS0029: Nie można niejawnie przekonwertować typu „string” na „int”.

Dwie liczby w nawiasie to linia i kolumna. Kolumna 12 wskazuje Console.ReadLine(), a nie deklarację zmiennej, i to jest pierwsza wskazówka:

Console.Write("Podaj swój wiek: ");
int wiek = Console.ReadLine();

Console.ReadLine() zwraca string. Zawsze, również wtedy, gdy użytkownik wpisze 20. Zmienna wiek jest typu int, więc kompilator ma po jednej stronie tekst, a po drugiej liczbę całkowitą, i żadna reguła języka nie mówi mu, co zrobić z wejściem „dwadzieścia” albo z samym Enterem. Zamiast wybierać za Ciebie, przerywa kompilację.

Poprawka nazywa operację wprost:

int wiek = int.Parse(Console.ReadLine());

int.Parse zgłasza FormatException, gdy tekst nie jest liczbą, więc w programie, który czyta cokolwiek od użytkownika, sensowniejszy jest int.TryParse:

if (int.TryParse(Console.ReadLine(), out int wiek))
{
    Console.WriteLine($"Za rok będziesz mieć {wiek + 1} lat.");
}
else
{
    Console.WriteLine("To nie jest liczba.");
}

Wpisane dwadzieścia daje wtedy To nie jest liczba. zamiast przerwanego programu.

Sam kompilator konwertuje niejawnie tylko wtedy, gdy nie da się przy tym nic stracić. int jest konwertowany na long i na double bez pytania, bo każda wartość int mieści się w obu. Dotyczy to nawet char na int:

char litera = 'K';
int kodZnaku = litera;

Kompiluje się i wypisuje 75, czyli kod znaku K. W drugą stronę, z int na char, kompilator wymaga już rzutowania, bo większość wartości int nie odpowiada żadnemu znakowi. Tekst i liczba nie mieszczą się w tej regule w żadną stronę, i stąd CS0029.

Dwa kolejne warianty: char na string i int na bool

Drugi pojawia się przy pierwszym sięgnięciu po znak z tekstu:

Program.cs(2,25): error CS0029: Nie można niejawnie przekonwertować typu „char” na „string”.

slowo[0] zwraca char, czyli pojedynczy znak, a nie tekst o długości jeden. C# nie traktuje jednego jako skróconej wersji drugiego, więc potrzebne jest slowo[0].ToString().

Trzeci wariant nie jest problemem z typami, tylko literówką, i dostajesz za niego taki komunikat:

Program.cs(4,5): error CS0029: Nie można niejawnie przekonwertować typu „int” na „bool”.

Winna jest jedna linia:

if (wiek = 18)

Jeden znak równości przypisuje, dwa porównują. Wyrażenie wiek = 18 ma wartość 18 i typ int, a if wymaga bool. W C, gdzie zero znaczy fałsz, taki kod skompilowałby się i cicho robił coś innego, niż zaplanowałeś. Ten sam upór kompilatora, który przy Console.ReadLine() wygląda na przeszkodę, tutaj wychwytuje błąd, którego sam byś nie znalazł.

Przypisania nie są przy tym jedynym miejscem. Ten sam numer wychodzi z instrukcji return, gdy metoda deklaruje int, a zwraca tekst:

Program.cs(5,12): error CS0029: Nie można niejawnie przekonwertować typu „string” na „int”.

Kolumna wskazuje wtedy wyrażenie po return, nie nagłówek metody.

CS0266 wygląda podobnie i wymaga czegoś innego

Jeśli w komunikacie pojawia się zdanie o konwersji jawnej, to nie ten błąd:

Program.cs(4,19): error CS0266: Nie można niejawnie przekonwertować typu „double” na „int”. Istnieje konwersja jawna (czy nie brakuje rzutu?).

Tu konwersja istnieje i kompilator ją zna. Nie wykona jej sam, bo (int) obcina część dziesiętną, a na utratę danych trzeba się zgodzić wprost. Rzutowanie (int)srednia jest tu całą poprawką.

Podział nie zależy od tego, czy typy są spokrewnione. object na string również daje CS0266, bo rzutowanie ma sens, nawet jeśli w czasie działania programu może się nie udać.

Przy CS0029 nie ma czego rzutować, więc ta sama próba kończy się kolejnym błędem:

Program.cs(1,12): error CS0030: Nie można przekonwertować typu „string” na „int”.

Dlatego rada „dodaj rzutowanie”, która powtarza się pod większością pytań o konwersję typów w C#, przy tym błędzie prowadzi w ślepą uliczkę. Najpierw sprawdź, czy komunikat wspomina o konwersji jawnej.

Komunikaty są po polsku, gdy język interfejsu systemu jest polski. Na angielskim Windowsie ten sam błąd brzmi Cannot implicitly convert type 'string' to 'int' i pod tą wersją znajdziesz więcej odpowiedzi.

W edytorze widać go jeszcze przed kompilacją, bo DevJourney uruchamia Roslyn Language Server, ten sam silnik, którego używa Visual Studio, i podkreśla obie strony przypisania od razu. Umiejętność przeczytania takiego komunikatu jest jedną z rzeczy, które realnie decydują o pierwszej pracy, a nie wybór języka.

Program kursu pokazuje, w jakiej kolejności układają się te podstawy.

Tematy: csharpbledypodstawy

Pobieranie ruszyło

DevJourney_1.0.0_x64-setup.exe · 1.0.0

Jeśli Windows ostrzeże

Komunikat „System Windows ochronił Twój komputer” nie oznacza wykrycia wirusa. SmartScreen ufa certyfikatowi, którym podpisany jest instalator, a ten jeszcze zbiera reputację poprzez licznik pobrań.

W oknie ostrzeżenia: Więcej informacji → Uruchom mimo to.

Sprawdź to sam

Zobacz wynik skanowania w VirusTotal

Albo w PowerShellu, w katalogu z pobranym plikiem:

Get-FileHash .\DevJourney_1.0.0_x64-setup.exe

Powinno wypisać:

7cd001be4463317f601b8bb2eed78537982a3559c92f06e96288434c79931fd6