2010-07-21 14 views
5

Rozważmy statyczną klasę testową:Dlaczego błędy rzucania C# rzucają podczas prób wykonywania operacji matematycznych na typach całkowitych innych niż int?

public static class Test 
{ 
    public static ushort sum(ushort value1, ushort value2) 
    { 
     return value1 + value2 
    } 
} 

To powoduje następujący błąd kompilacji, z value1 + value2 podkreślone na czerwono:

nie można niejawnie przekonwertować typu 'int' do 'ushort'. Istnieje wyraźna konwersja (czy brakuje Ci obsady)?

Dlaczego?

+0

Kompilator prosi użytkownika o wyraźne informowanie o tym, że dokonujesz zawężającej konwersji, w wyniku której dane mogą zostać utracone. Jeśli przejdziesz w ushort.MaxValue i 1, co powinno się stać? To jest pytanie, które kompilator przypomina ci o odpowiedzi. –

+0

@Dan: Powinno się zdarzyć, że 'ushort' powinien automatycznie przepełnić lub wyrzucić wyjątek przepełnienia, jeśli użyte jest słowo kluczowe' checked'. Jeśli dodasz dwie wartości 'int', nie otrzymasz tego samego błędu kompilatora, mimo że możliwe jest przepełnienie. –

+0

Moje ujęcie: przepełnienie to coś, co pojawia się w wyniku operacji, a nie zadania. W szczególności można przepełnić w trakcie złożonych obliczeń, nawet jeśli ostateczny wynik byłby w zakresie. Jeśli wystąpi przepełnienie, matematyka nie działa zgodnie z oczekiwaniami, ale nie ma to miejsca podczas dodawania dwóch usortowań w systemie 32-bitowym. Matematyka działała dobrze, ale teraz musisz zdecydować, jak interpretować wynik. Jeśli chcesz, aby przepełnienie zostało zmienione, możesz rzucić go bezpośrednio do ushorta. Może się to zdarzyć niejawnie, ale pomocna jest wymagająca jawna obsada. –

Odpowiedz

7

Podobnie jak C i C++ przed nim, liczby całkowite są niejawnie rozszerzone, gdy są używane z wieloma operatorami. W takim przypadku wynikiem dodania razem dwóch wartości ushort jest int.

Aktualizacja:

Więcej informacji: http://msdn.microsoft.com/en-us/library/aa691330(v=VS.71).aspx

Wierzę, że ten został dodany w C/C++, ponieważ int był rodzimy typ całkowity (i tak, operacje były szybsze na int s niż na short s na architekturach 32-bitowych). Nie jestem pewien co do pełnego uzasadnienia dla C#.

To sprawia, że ​​myślisz o rozważaniach dotyczących przelania/skrócenia podczas rzutowania. Przypadkowe przepełnienie jest bardziej prawdopodobne w przypadku mniejszych typów całkowitych.

+0

Czyli tak się dzieje, ponieważ zawsze było to robione w ten sposób? –

+0

Ponieważ konwersje muszą mimo wszystko istnieć, łatwiej jest przekonwertować je na jeden typ i zastosować operatorów, niż zaimplementować operatorów osobno dla każdego typu ponad już istniejącymi konwersjami. – murgatroid99

+2

To, a maszyna domyślnie robi arytmetyczne jako "int". Ponadto, jeśli istnieje wiele niejawnych konwersji, staje się o wiele bardziej prawdopodobne, że kompilator wybierze konwersję, której tak naprawdę nie zamierzałeś. (Patrz na przykład PL/I). –

5

ushort

Poniższy instrukcji przypisania spowoduje błąd kompilacji, ponieważ wyrażenie arytmetyczne na prawa strona dłoni operatora przypisania ocenia int domyślnie.

ushort z = x + y; // Error: conversion from int to ushort 

Aby rozwiązać ten problem, należy użyć Obsada:

ushort z = (ushort)(x + y); // OK: explicit conversion 
2

Dostępne operatory dodawania w C# kontemplować tylko int, uint, long i ulong typy danych więc w tym przypadku domyślnie rzutujesz dwie instancje ushort na int, a następnie wykonując dodawanie i pl zwrócenie int, którego nie można domyślnie przenieść na ushort.

Ze specyfikacji C# 4.0, sekcja 7.8.4 Dodanie operator, można sprawdzić, że tylko następujące operatory dodawania całkowitymi są dostępne:

int operator +(int x, int y); 
uint operator +(uint x, uint y); 
long operator +(long x, long y); 
ulong operator +(ulong x, ulong y); 

tej samej sekcji stwierdza również:

Argumenty są konwertowane do typów parametrów wybranego operator, a typ wyniku jest typem zwrotu operatora.

Co tłumaczy, dlaczego wyrażenie to powoduje int.

1

Dzieje się tak dlatego, że dodawanie lub odejmowanie ushort nie musi oznaczać, że zostanie użyty. Na przykład wynikiem może być < 0, która nie jest ushortem. Musisz więc podać kompilatorowi podpowiedź, aby nie narzekała, odlewając ją. Wierzę, że to powinno działać: return (ushort) (value1 + value2);

Powiązane problemy