2010-01-06 24 views
61

Acabo de intentar implementar una clase donde numerosas propiedades de longitud/conteo, etc. son uint en lugar de int. Sin embargo, al hacerlo noté que en realidad es doloroso hacerlo, como si realmente nadie quisiera hacer eso.¿Debo usar uint en C# para valores que no pueden ser negativos?

Casi todo lo que entrega un tipo integral devuelve un int, por lo que requiere moldes en varios puntos. Quería construir un StringBuffer con su longitud de buffer predeterminada en uno de los campos de esa clase. Requiere un yeso también.

Así que me preguntaba si debería volver a int aquí. Ciertamente, no estoy usando toda la gama de todos modos. Solo pensé que, dado que lo que estoy tratando allí, simplemente no puede ser negativo (si lo fuera, sería un error) sería una buena idea usar realmente uint.

P.S .: vi this question y esto explica por qué, al menos, el propio marco siempre utiliza int pero incluso en el propio código en realidad es engorroso para pegarse a uint que me hace pensar que, aparentemente, no está realmente quería.

+0

Ver también [why-does-net-use-int-instead-of-uint-in-certain-classes] (http://stackoverflow.com/questions/782629/why-does-net-use-int -instead-of-uint-in-certain-classes) – nawfal

Respuesta

36

Si bien estrictamente debe usar uint para las variables que contienen números enteros no negativos, ha encontrado una de las razones por las que no siempre es posible.

En este caso, no creo que valga la pena la reducción en la legibilidad que se obtiene al tener que hacer moldes.

+2

Es difícil de decir, no creo que los moldes reduzcan la legibilidad mucho solo para los indexadores y puedes crear un envoltorio. Y las inyecciones que se vuelven negativas son insectos dolorosos y costosos. – user1496062

+3

Si tiene que crear un contenedor para un int, entonces tiene más problemas de legibilidad :) – Sam

3

Mi sensación personal es que probablemente deberías simplemente quedarte con int. No vale la pena agregar un elenco a casi todos los accesos de propiedad solo para reclamar un rango numérico que es poco probable que .NET le permita usar de todos modos.

4

Un valor negativo se utiliza a menudo para señalar una condición de error, y el tamaño de una operación a menudo es devuelto por una llamada a la función; un valor negativo puede, por lo tanto, indicar un error sin recurrir a un mecanismo de excepción.

También tenga en cuenta que .NET a menudo se basa en bibliotecas C rectas, por lo tanto, es sensato continuar esta convención. Si necesita un espacio de índice mayor, puede romper la convención para un mecanismo de señalización de error diferente.

+19

.NET es bastante consistente con arrojar excepciones en lugar de devolver códigos de error. El retorno de -1 no es algo común en el código administrado. – ChrisV

+0

estuvo de acuerdo, pero estamos hablando de una convención de diseño que prevalece en todas las tecnologías de Windows (además de las excepciones donde son compatibles): aquellas partes de la biblioteca .NET que interactúan con el código de bajo nivel tienen que traducir entre los códigos de error CRT y Excepciones: es comprensible por qué presentan la convención de int en lugar de uint's. –

1

Si desea comprobar que un valor es positivo, una mejor manera es probablemente usar assert (tenga en cuenta que esta es solo una técnica de depuración, debe asegurarse de que esto nunca ocurra en el código final).

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

El uso de una int también es útil para detectar el desbordamiento de enteros en las operaciones.

50

Agregaré a las otras respuestas también que usar uint como tipo de campo público, propiedad, método, parámetro, etc., es una violación de las reglas de la especificación de lenguaje común y debe evitarse cuando sea posible.

+2

Y me quemó por parte de Microsoft siguiendo estrictamente eso. Resulta que IntPtr debería haber tenido un constructor uint. – Joshua

+1

También agregaría que si admitieran números naturales; por ejemplo, este tipo tiene un valor de 0 a 6, podrían eliminar toda la comprobación de límites de matriz, un enorme incremento de rendimiento del 5-10%. – user1496062

3

IMO, el inconveniente de usar uint es que oculta las condiciones de error. Los equivalentes del siguiente código no son tan bonitas:

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

Por supuesto sus programas no se debe calcular mal nada para empezar, pero creo que también deben ser escritos para detectar rápidamente y sin erros numéricos de propagación.En el caso donde un MaxValue de 2^31 es suficiente, digo use int junto con el uso apropiado de System.Diagnostics.Debug.Assert() y las verificaciones de error correspondientes como se ejemplificó anteriormente.

Si utiliza uint, úselo junto con checked para evitar subdesbordamientos y obtener los mismos resultados. Sin embargo, he encontrado que el control es un poco difícil de aplicar al código existente que usa moldes para algún propósito.

1

No nades río arriba si no tienes que hacerlo. El hecho de no mezclar su código con moldes hace que su código sea más legible. Además, si sus valores posibles encajan dentro de un int, entonces usar un int no es un problema.

Si tiene miedo de que pueda desbordar un int, entonces hay que hacerlo ... pero no optimice prematuramente.

Yo diría que la legibilidad mejorada de los moldes minimiza el riesgo ligeramente elevado de un error al usar int.

Cuestiones relacionadas