2010-01-06 10 views
61

Ho appena provato a implementare una classe in cui numerose proprietà di lunghezza/conteggio, ecc. Sono uint anziché int. Tuttavia, mentre lo facevo, ho notato che è davvero doloroso farlo, come se nessuno volesse davvero farlo.Devo usare uint in C# per valori che non possono essere negativi?

Quasi tutto ciò che fornisce un tipo integrale restituisce un int, pertanto richiede cast in diversi punti. Volevo costruire un StringBuffer con la sua lunghezza del buffer predefinita per uno dei campi in quella classe. Richiede anche un cast.

Quindi mi chiedevo se dovessi tornare a int qui. Certamente non sto usando l'intera gamma comunque. Ho solo pensato che dal momento che quello che sto trattando semplicemente non può essere negativo (se lo fosse, sarebbe un errore) sarebbe una buona idea usare effettivamente uint.

P.S .: Ho visto this question e questo, almeno spiega perché il framework stesso utilizza sempre int ma anche nel proprio codice in realtà è ingombrante di attenersi a uint che mi fa pensare a quanto pare non è veramente voluto.

+0

Vedere anche [why-does-net-use-int-invece-of-uint-in-certain-classes] (http://stackoverflow.com/questions/782629/why-does-net-use-int -instead-of-uint-in-certain-classes) – nawfal

risposta

36

Mentre è strettamente necessario utilizzare uint per le variabili che contengono numeri interi non negativi, si è imbattuto in uno dei motivi per cui non è sempre praticabile.

In questo caso non credo che valga la pena ridurre la leggibilità che deriva dal dover eseguire cast.

+2

È difficile dirlo, non penso che i cast riducano molto la leggibilità solo per gli indicizzatori e puoi creare un wrapper. E quelli che diventano negativi sono insetti dolorosi e costosi. – user1496062

+3

Se si deve creare un wrapper per un int, allora si hanno più problemi di leggibilità :) – Sam

3

La mia sensazione personale è che probabilmente dovresti limitarti a int. Non vale la pena aggiungere un cast a praticamente tutti gli accessi alle proprietà solo per recuperare un intervallo numerico che è improbabile che .NET possa comunque utilizzare.

4

Un valore negativo viene spesso utilizzato per segnalare una condizione di errore e la dimensione di un'operazione viene spesso restituita da una chiamata di funzione; un valore negativo può quindi segnalare un errore senza ricorrere a un meccanismo di eccezione.

Si noti inoltre che .NET spesso si basa su librerie C diritte, pertanto è ragionevole continuare questa convenzione. Se si richiede uno spazio indice più grande, è possibile interrompere la convenzione per un diverso meccanismo di segnalazione degli errori.

+19

.NET è piuttosto coerente con le eccezioni di lancio anziché restituire i codici di errore. Il ritorno -1 non è una vista comune nel codice gestito. – ChrisV

+0

concordato, ma stiamo parlando di una convenzione di progettazione che è diffusa in tutte le tecnologie di Windows (oltre alle eccezioni dove sono supportate) - quelle parti della libreria .NET che si interfacciano con codice di basso livello devono tradurre tra i codici di errore CRT e eccezioni - è comprensibile perché portino avanti la convenzione di int piuttosto che di uint. –

1

Se si desidera verificare che un valore sia positivo, un modo migliore è probabilmente solo utilizzando assert (notare che questa è solo una tecnica di debug - è necessario assicurarsi che ciò non si verifichi mai nel codice finale).

using System.Diagnostics; 
... 
Debug.Assert (i > 0); 
3

L'utilizzo di un int è anche utile per rilevare l'overflow dei numeri interi nelle operazioni.

50

Aggiungerò alle altre risposte anche che usare uint come tipo di campo pubblico, proprietà, metodo, parametro e così via, è una violazione delle regole di Common Language Specification e deve essere evitato quando possibile.

+2

E sono stato bruciato da Microsoft seguendo rigorosamente quello. Si scopre che IntPtr avrebbe dovuto avere un costruttore di uint. – Joshua

+1

Aggiungerei anche se supportassero numeri naturali, ad es. Questo tipo è il valore da 0 a 6, potrebbero eliminare tutti i controlli sui limiti di array, un enorme incremento delle prestazioni del 5-10%. – user1496062

3

IMO, l'inconveniente di utilizzare uint è che oscura le condizioni di errore. Gli equivalenti del codice seguente non sono belle:

if (len < 0) 
    terminate_program("length attained impossible value."); 

Naturalmente i vostri programmi non dovrebbero sbagliare nulla per cominciare, ma mi sento anche devono essere scritti per rilevare rapidamente erros numerici, senza propagazione.Nel caso in cui un MaxValue di 2^31 sia sufficiente, dico usare int insieme all'uso corretto di System.Diagnostics.Debug.Assert() e i corrispondenti controlli di errore come esemplificato sopra.

Se si utilizza uint usarlo insieme a checked per impedire l'underflow e ottenere gli stessi risultati. Tuttavia ho trovato che il controllo è un po 'difficile da applicare al codice esistente che utilizza i cast per qualche scopo.

1

Non nuotare controcorrente se non è necessario. Non leggere il codice con i cast rende il tuo codice più leggibile. Inoltre, se i valori possibili si adattano a un int, quindi l'utilizzo di un int non è un problema.

Se si ha paura di un overflow di un int, allora ci sono tutti i mezzi .. ma non ottimizzarlo prematuramente.

Direi che la leggibilità migliorata della riduzione al minimo dei cast supera il rischio leggermente elevato di un bug nell'utilizzo di int.

Problemi correlati