Błąd kompilatora CS0029

Nie można niejawnie przekonwertować typu "type" na typ

Kompilator wymaga jawnej konwersji. Na przykład może być konieczne rzutowanie wartości r jako tego samego typu co l-wartość. Możesz też podać procedury konwersji, aby obsługiwać pewne przeciążenia operatora.

Konwersje muszą wystąpić podczas przypisywania zmiennej jednego typu do zmiennej innego typu. Podczas przypisywania między zmiennymi różnych typów kompilator musi przekonwertować typ po prawej stronie operatora przypisania na typ po lewej stronie operatora przypisania. Wykonaj następujący kod:

int i = 50;
long lng = 100;
i = lng;

i = lng; tworzy przypisanie, ale typy danych zmiennych po lewej i prawej stronie operatora przypisania nie są zgodne. Przed przypisaniem kompilator niejawnie konwertuje zmienną lng, która jest typu długa, na int. Jest to niejawne, ponieważ żaden kod jawnie nie polecił kompilatorowi wykonania tej konwersji. Problem z tym kodem polega na tym, że jest to uważane za konwersję zawężającą, a kompilator nie zezwala na niejawne konwersje zawężające, ponieważ może dojść do potencjalnej utraty danych.

Konwersja zawężająca istnieje podczas konwertowania na typ danych, który zajmuje mniej miejsca do magazynowania w pamięci niż typ danych, z którego się konwertujemy. Na przykład przekonwertowanie długości na int byłoby traktowane jako konwersja zawężająca. Długość zajmuje 8 bajtów pamięci, podczas gdy liczba bajtów zajmuje 4 bajty. Aby zobaczyć, jak może wystąpić utrata danych, rozważmy następujący przykład:

int i = 50;
long lng = 3147483647;
i = lng;

Zmienna lng zawiera teraz wartość, której nie można przechowywać w zmiennej i , ponieważ jest zbyt duża. Gdybyśmy przekonwertowali tę wartość na typ int, utracilibyśmy część naszych danych, a przekonwertowana wartość nie byłaby taka sama jak wartość przed konwersją.

Konwersja rozszerzająca byłaby przeciwieństwem konwersji zawężającej. W przypadku konwersji rozszerzających konwertujemy na typ danych, który zajmuje więcej miejsca w pamięci niż typ danych, z którego się konwertujemy. Oto przykład konwersji rozszerzającej:

int i = 50;
long lng = 100;
lng = i;

Zwróć uwagę na różnicę między tym przykładem kodu a pierwszą. Tym razem zmienna lng znajduje się po lewej stronie operatora przypisania, więc jest to element docelowy naszego przypisania. Przed dokonaniem przypisania kompilator musi niejawnie przekonwertować zmienną i, która jest typu int, na typ długi. Jest to konwersja rozszerzająca, ponieważ konwertujemy z typu, który zajmuje 4 bajty pamięci (int) do typu, który zajmuje 8 bajtów pamięci (długiej). Niejawne konwersje rozszerzające są dozwolone, ponieważ nie ma potencjalnej utraty danych. Dowolna wartość, którą można przechowywać w int, może być również przechowywana w długim czasie.

Wiemy, że niejawne konwersje zawężania są niedozwolone, więc aby móc skompilować ten kod, musimy jawnie przekonwertować typ danych. Konwersje jawne są wykonywane przy użyciu rzutu. Rzutowanie to termin używany w języku C# do opisywania konwertowania jednego typu danych na inny. Aby uzyskać kod do skompilowania, musimy użyć następującej składni:

int i = 50;
long lng = 100;
i = (int) lng;   // Cast to int.

Trzeci wiersz kodu nakazuje kompilatorowi jawne przekonwertowanie zmiennej lng, która jest typu długa, na int przed dokonaniem przypisania. Pamiętaj, że w przypadku konwersji zawężającej istnieje potencjalna utrata danych. Konwersje zawężania powinny być używane z ostrożnością, a mimo że kod skompilowany może uzyskać nieoczekiwane wyniki w czasie wykonywania.

Ta dyskusja dotyczy tylko typów wartości. Podczas pracy z typami wartości pracujesz bezpośrednio z danymi przechowywanymi w zmiennej. Jednak platforma .NET ma również typy referencyjne. Podczas pracy z typami referencyjnymi pracujesz z odwołaniem do zmiennej, a nie z rzeczywistymi danymi. Przykłady typów odwołań to klasy, interfejsy i tablice. Nie można niejawnie ani jawnie przekonwertować jednego typu odwołania na inny, chyba że kompilator zezwala na konkretną konwersję lub odpowiednie operatory konwersji są implementowane.

Poniższy przykład generuje plik CS0029:

// CS0029.cs
public class MyInt
{
    private int x = 0;

    // Uncomment this conversion routine to resolve CS0029.
    /*
    public static implicit operator int(MyInt i)
    {
        return i.x;
    }
    */

    public static void Main()
    {
        var myInt = new MyInt();
        int i = myInt; // CS0029
    }
}

Zobacz też