not - string null c#
¿Por qué está "nulo" presente en C#y Java? (25)
Notamos que muchos errores en nuestro software desarrollado en C # (o Java) causan una NullReferenceException.
¿Hay alguna razón por la cual "nulo" haya sido incluido en el lenguaje?
Después de todo, si no hubiera un "nulo", no tendría ningún error, ¿verdad?
En otras palabras, ¿qué función del lenguaje no podría funcionar sin nulo?
Después de todo, si no hubiera un "nulo", no tendría ningún error, ¿verdad?
La respuesta es NO . El problema no es que C # permita nulo, el problema es que tiene errores que se manifiestan con la NullReferenceException. Como se ha indicado anteriormente, los valores nulos tienen un propósito en el lenguaje para indicar un tipo de referencia "vacío" o un valor nulo (vacío / nada / desconocido).
"Nulo" está incluido en el idioma porque tenemos tipos de valores y tipos de referencia. Probablemente sea un efecto secundario, pero creo que es bueno. Nos da mucho poder sobre cómo administramos la memoria de manera efectiva.
¿Por qué tenemos nulo? ...
Los tipos de valores se almacenan en la "pila", su valor se encuentra directamente en esa pieza de memoria (es decir, int x = 5 significa que la ubicación de la memoria para esa variable contiene "5").
Por otro lado, los tipos de referencia tienen un "puntero" en la pila apuntando al valor real en el montón (es decir, la cadena x = "ello" significa que el bloque de memoria en la pila solo contiene una dirección que apunta al valor real en el montón )
Un valor nulo simplemente significa que nuestro valor en la pila no apunta a ningún valor real en el montón: es un puntero vacío.
Espero haber explicado eso lo suficientemente bien.
Además de TODAS las razones ya mencionadas, NULL es necesario cuando necesita un marcador de posición para un objeto aún no creado. Por ejemplo. si tiene una referencia circular entre un par de objetos, entonces necesita nulo ya que no puede instanciar ambos simultáneamente.
class A {
B fieldb;
}
class B {
A fielda;
}
A a = new A() // a.fieldb is null
B b = new B() { fielda = a } // b.fielda isnt
a.fieldb = b // now it isnt null anymore
Editar: es posible que pueda extraer un idioma que funcione sin nulos, pero definitivamente no será un lenguaje orientado a objetos. Por ejemplo, prolog no tiene valores nulos.
Anders Hejlsberg, "C # father", acaba de hablar de ese punto en su entrevista de Computerworld :
Por ejemplo, en el sistema de tipos no tenemos separación entre el valor y los tipos de referencia y la nulabilidad de los tipos. Esto puede sonar un poco torpe o un poco técnico, pero en C # los tipos de referencia pueden ser nulos, como cadenas, pero los tipos de valores no pueden ser nulos. Seguramente sería bueno tener tipos de referencia que no admiten nulos, por lo que podría declarar que "esta cadena nunca puede ser nula, y quiero que el compilador compruebe que nunca puedo presionar un puntero nulo aquí".
El 50% de los errores con los que se topan las personas hoy en día, la codificación con C # en nuestra plataforma, y lo mismo ocurre con Java en este caso, son probablemente excepciones de referencia nulas. Si tuviéramos un sistema de tipo más fuerte que le permitiera decir que ''este parámetro nunca puede ser nulo, y su compilador, por favor verifique que en cada llamada, haciendo un análisis estático del código''. Entonces podríamos haber eliminado clases de errores.
Cyrus Najmabadi, un ex ingeniero de diseño de software del equipo C # (que ahora trabaja en Google) discute sobre ese tema en su blog: ( 1st , 2nd , 3rd 4th , 4th ). Parece que el mayor obstáculo para la adopción de tipos que no admiten nulos es que la notación alteraría los hábitos de los programadores y la base de códigos. Algo así como el 70% de las referencias de los programas de C # es probable que terminen como los que no admiten nulos.
Si realmente desea tener un tipo de referencia que no admite nulos en C #, debe intentar usar Spec# que es una extensión de C # que permite el uso de "!" como un signo que no admite nulos
static string AcceptNotNullObject(object! s)
{
return s.ToString();
}
Comúnmente, NullReferenceException significa que a algún método no le gustó lo que se le entregó y devolvió una referencia nula, que luego se usó sin verificar la referencia antes de su uso.
Ese método podría haber arrojado una excepción más detallada en lugar de devolver el valor nulo, que cumple con el modo de pensamiento fallido .
O el método puede devolver el valor nulo como una conveniencia para usted, de modo que puede escribir si en lugar de tratar de evitar la "sobrecarga" de una excepción.
Como muchas cosas en la programación orientada a objetos, todo se remonta a ALGOL. Tony Hoare simplemente lo llamó su "error de un billón de dólares". En todo caso, eso es un eufemismo.
Aquí hay una tesis realmente interesante sobre cómo hacer que la nulabilidad no sea la predeterminada en Java. Los paralelos a C # son obvios.
Eliminar null no resolvería mucho. Necesitará tener una referencia predeterminada para la mayoría de las variables que se establece en init. En lugar de excepciones de referencia nula, se obtendría un comportamiento inesperado porque la variable apunta a los objetos incorrectos. Al menos las referencias nulas fallan rápidamente en lugar de causar un comportamiento inesperado.
Puede ver el patrón de objetos nulos para encontrar una forma de resolver parte de este problema
Hay situaciones en las que null es una buena forma de indicar que una referencia no se ha inicializado. Esto es importante en algunos escenarios.
Por ejemplo:
MyResource resource;
try
{
resource = new MyResource();
//
// Do some work
//
}
finally
{
if (resource != null)
resource.Close();
}
En la mayoría de los casos, esto se logra mediante el uso de una declaración de uso . Pero el patrón todavía se usa ampliamente.
Con respecto a su NullReferenceException, la causa de tales errores a menudo es fácil de reducir mediante la implementación de un estándar de codificación donde todos los parámetros a verifican su validez. Dependiendo de la naturaleza del proyecto, me parece que en la mayoría de los casos es suficiente verificar los parámetros en los miembros expuestos. Si los parámetros no están dentro del rango esperado, se lanza una ArgumentException de algún tipo, o se devuelve un resultado de error, dependiendo del patrón de manejo de errores en uso.
La verificación de parámetros no elimina los errores, pero cualquier error que ocurra es más fácil de localizar y corregir durante la fase de prueba.
Como nota, Anders Hejlsberg ha mencionado la falta de aplicación no nula como uno de los mayores errores en la especificación C # 1.0 y que incluirla ahora es "difícil".
Si aún cree que un valor de referencia no nulo impuesto de forma estática es de gran importancia, puede consultar el spec# idioma de la spec# . Es una extensión de C # donde las referencias no nulas son parte del lenguaje. Esto garantiza que nunca se puede asignar una referencia nula a una referencia marcada como no nula.
La característica que no podría funcionar sin nulo es ser capaz de representar "la ausencia de un objeto".
La ausencia de un objeto es un concepto importante. En la programación orientada a objetos, la necesitamos para representar una asociación entre objetos que es opcional: el objeto A puede adjuntarse a un objeto B, o A podría no tener un objeto B. Sin nulo aún podríamos emular esto: por ejemplo podríamos usar una lista de objetos para asociar B con A. Esa lista podría contener un elemento (una B), o estar vacía. Esto es un poco inconveniente y realmente no resuelve nada. El código que asume que hay una B, como aobj.blist.first().method()
va a explotar de forma similar a una excepción de referencia nula: (si blist
está vacío, ¿cuál es el comportamiento de blist.first()
?)
Hablando de listas, null le permite terminar una lista vinculada. Un ListNode
puede contener una referencia a otro ListNode
que puede ser nulo. Lo mismo puede decirse sobre otras estructuras de conjuntos dinámicos como los árboles. Null le permite tener un árbol binario ordinario cuyos nodos hoja están marcados por tener referencias secundarias que son nulas.
Las listas y los árboles se pueden construir sin nulo, pero tienen que ser circulares, o infinitos / perezosos. Eso probablemente sería considerado como una restricción inaceptable por la mayoría de los programadores, que preferirían tener opciones para diseñar estructuras de datos.
Los dolores asociados con referencias nulas, como referencias nulas que surgen accidentalmente debido a errores y causan excepciones, son parcialmente una consecuencia del sistema de tipo estático, que introduce un valor nulo en cada tipo: hay una cadena nula, un entero nulo, un nulo Widget, ...
En un lenguaje de tipado dinámico, puede haber un solo objeto nulo, que tiene su propio tipo. El resultado de esto es que tiene todas las ventajas representativas de nulo, además de una mayor seguridad. Por ejemplo, si escribe un método que acepta un parámetro de cadena, entonces se le garantiza que el parámetro será un objeto de cadena, y no nulo. No hay referencia nula en la clase String: algo que se sabe que es una cadena no puede ser el objeto nulo. Las referencias no tienen texto en un lenguaje dinámico. Una ubicación de almacenamiento como un miembro de clase o un parámetro de función contiene un valor que puede ser una referencia a un objeto. Ese objeto tiene tipo, no la referencia.
Entonces estos lenguajes proporcionan un modelo limpio, más o menos matematicamente puro de "nulo", y luego los estáticos lo convierten en un monstruo de Frankenstein.
La nulidad es una consecuencia natural de los tipos de referencia. Si tiene una referencia, debe referirse a algún objeto, o ser nulo. Si tuviera que prohibir la nulidad, siempre debería asegurarse de que cada variable se haya inicializado con alguna expresión que no sea nula, y aun así tendría problemas si las variables se leyeran durante la fase de inicialización.
¿Cómo propondrías eliminar el concepto de nulidad?
La pregunta puede interpretarse como "¿Es mejor tener un valor predeterminado para cada tipo de referencia (como String.Empty) o nulo?". En esta perspectiva, preferiría tener nulos, porque;
- No me gustaría escribir un constructor predeterminado para cada clase que escribo.
- No me gustaría que se asignara una memoria innecesaria para dichos valores predeterminados.
- Comprobar si un referance es nulo es bastante más barato que las comparaciones de valores.
- Es muy posible tener más errores que sean más difíciles de detectar, en lugar de NullReferanceExceptions. Es bueno tener una excepción que indique claramente que estoy haciendo (asumiendo) algo incorrecto.
Me sorprende que nadie haya hablado sobre las bases de datos para su respuesta. Las bases de datos tienen campos anulables, y cualquier lenguaje que recibirá datos de un DB debe manejar eso. Eso significa tener un valor nulo.
De hecho, esto es tan importante que para tipos básicos como int puedes hacer que sean nulables.
También considere los valores de retorno de las funciones, ¿qué pasa si usted quiere tener una función para dividir un par de números y el denominador podría ser 0? La única respuesta "correcta" en tal caso sería nula. (Lo sé, en un ejemplo tan simple, una excepción sería probablemente una mejor opción ... pero puede haber situaciones en las que todos los valores son correctos pero los datos válidos pueden producir una respuesta inválida o incalculable. No estoy seguro de que se deba usar una excepción en tales casos...)
No puedo hablar sobre su problema específico, pero parece que el problema no es la existencia de un nulo. Nulo existe en las bases de datos, necesita alguna manera de dar cuenta de eso en el nivel de la aplicación. No creo que esa sea la única razón por la que existe en .net, fíjate. Pero creo que es una de las razones.
Null es una característica extremadamente poderosa. ¿Qué haces si tienes una ausencia de un valor? ¡Es NULO!
Una escuela de pensamiento es nunca regresar nula, otra es siempre. Por ejemplo, algunos dicen que debe devolver un objeto válido pero vacío.
Prefiero nulo como para mí es una indicación más verdadera de lo que realmente es. Si no puedo recuperar una entidad de mi capa de persistencia, quiero nulo. No quiero un valor vacío Pero ese soy yo.
Es especialmente útil con primitivos. Por ejemplo, si tengo verdadero o falso, pero se usa en un formulario de seguridad, donde un permiso puede ser Permitir, Denegar o no establecer. Bueno, quiero que no sea nulo. ¿Entonces puedo usar bool?
Hay mucho más sobre lo que podría hablar, pero lo dejaré allí.
Null no causa NullPointerExceptions ...
Los programadores causan NullPointerExceptions.
Sin valores nulos volvemos a utilizar un valor arbitrario real para determinar que el valor de retorno de una función o método no es válido. Todavía tiene que comprobar el -1 devuelto (o lo que sea), eliminar nulos no resolverá mágicamente la pereza, sino que meramente la ofuscará.
Nulo es un requisito esencial de cualquier lenguaje OO. Cualquier variable de objeto que no haya sido asignada a una referencia de objeto debe ser nula.
Nulo, ya que está disponible en C # / C ++ / Java / Ruby se ve mejor como una rareza de un pasado oscuro (Algol) que de alguna manera sobrevivió hasta el día de hoy.
Lo usas de dos maneras:
- Para declarar referencias sin inicializarlas (mal).
- Para denotar la opción (OK).
Como habrás adivinado, 1) es lo que nos causa interminables problemas en los lenguajes imperativos comunes y debería haber sido prohibido hace mucho tiempo, 2) es la verdadera característica esencial.
Hay idiomas que evitan 1) sin evitar 2).
Por ejemplo OCaml es ese lenguaje.
Una función simple que devuelve un entero cada vez mayor a partir de 1:
let counter = ref 0;;
let next_counter_value () = (counter := !counter + 1; !counter);;
Y con respecto a la opcionalidad:
type distributed_computation_result = NotYetAvailable | Result of float;;
let print_result r = match r with
| Result(f) -> Printf.printf "result is %f/n" f
| NotYetAvailable -> Printf.printf "result not yet available/n";;
Perdón por responder cuatro años tarde, me sorprende que ninguna de las respuestas hasta ahora haya respondido la pregunta original de esta manera:
Los lenguajes como C # y Java , como C y otros idiomas antes que ellos, tienen null
para que el programador pueda escribir código rápido y optimizado usando punteros de una manera eficiente.
- Vista de bajo nivel
Un poco de historia primero. La razón por la cual se inventó null
es por eficiencia. Al realizar una programación de bajo nivel en el ensamblado, no hay abstracción, tiene valores en los registros y desea aprovecharlos al máximo. Definir cero para que no sea un valor de puntero válido es una estrategia excelente para representar un objeto o nada .
¿Por qué desperdiciar la mayor parte de los valores posibles de una palabra de memoria perfectamente buena, cuando se puede tener una implementación de memoria de cero sobrecarga, realmente rápida del patrón de valor opcional ? Esta es la razón por la cual null
es tan útil.
- Vista de alto nivel
Semánticamente, null
es de ninguna manera necesario para los lenguajes de programación. Por ejemplo, en los lenguajes funcionales clásicos como Haskell o en la familia ML, no hay nulo, sino más bien tipos llamados Maybe u Option. Representan el concepto de alto nivel de valor opcional sin preocuparse en modo alguno por cómo se verá el código ensamblado generado (ese será el trabajo del compilador).
Y esto también es muy útil, porque permite al compilador detectar más errores , y eso significa menos NullReferenceExceptions.
- Reuniéndolos
A diferencia de estos lenguajes de programación de alto nivel, C # y Java permiten un valor posible de nulo para cada tipo de referencia (que es otro nombre para el tipo que terminará implementándose mediante punteros ).
Esto puede parecer algo malo, pero lo bueno de esto es que el programador puede usar el conocimiento de cómo funciona bajo el capó, para crear un código más eficiente (a pesar de que el lenguaje tiene recolección de basura).
Esta es la razón por la cual todavía existe null
en los idiomas en la actualidad: una compensación entre la necesidad de un concepto general de valor opcional y la necesidad siempre presente de eficiencia.
Propongo:
- Ban Null
- Extiende Booleanos: True, False y FileNotFound
Si crea un objeto con una variable de instancia que es una referencia a algún objeto, ¿qué valor sugeriría tiene esta variable antes de asignarle cualquier referencia de objeto?
Si obtiene una ''NullReferenceException'', tal vez siga refiriéndose a los objetos que ya no existen. Esto no es un problema con ''nulo'', es un problema con su código que apunta a direcciones inexistentes.
Si un marco permite la creación de una matriz de algún tipo sin especificar qué se debe hacer con los nuevos elementos, ese tipo debe tener algún valor predeterminado. Para los tipos que implementan la semántica de referencia mutable (*), en general no hay ningún valor predeterminado razonable. Considero que es una debilidad del framework .NET que no hay forma de especificar que una llamada a función no virtual debería suprimir cualquier verificación nula. Esto permitiría que tipos inmutables como String se comporten como tipos de valor, al devolver valores razonables para propiedades como Length.
(*) Tenga en cuenta que en VB.NET y C #, la semántica de referencia mutable puede ser implementada por clase o tipo de estructura; un tipo de estructura implementaría una semántica de referencia mutable al actuar como un proxy para una instancia envuelta de un objeto de clase al que tiene una referencia inmutable.
También sería útil si se pudiera especificar que una clase debe tener una semántica de tipo de valor mutable no anulable (lo que implica que, como mínimo, la creación de instancias de un campo de ese tipo crearía una nueva instancia de objeto usando un constructor predeterminado, y copiar un campo de ese tipo crearía una nueva instancia copiando el anterior (manejando recursivamente cualquier clase de valor anidado).
Sin embargo, no está claro exactamente cuánto apoyo se debe incorporar en el marco para esto. Tener el propio marco reconocer las distinciones entre tipos de valores mutables, tipos de referencia mutables y tipos inmutables, permitiría que las clases que tienen referencias a una mezcla de tipos mutables e inmutables de clases externas eviten eficientemente hacer copias innecesarias de objetos profundamente inmutables.
Una respuesta mencionó que hay nulos en las bases de datos. Eso es cierto, pero son muy diferentes de los nulos en C #.
En C #, los nulos son marcadores para una referencia que no se refiere a nada.
En las bases de datos, los nulos son marcadores para las celdas de valor que no contienen un valor. Por celdas de valor, generalmente me refiero a la intersección de una fila y una columna en una tabla, pero el concepto de celdas de valor podría extenderse más allá de las tablas.
La diferencia entre los dos parece trivial, en un primer momento. Pero no lo es.
Null en C # es principalmente un arrastre de C ++, que tenía punteros que no apuntaban a nada en la memoria (o más bien, dirección 0x00
). En esta entrevista , Anders Hejlsberg dice que le hubiera gustado agregar tipos de referencia que no admiten nulos en C #.
Null también tiene un lugar legítimo en un sistema de tipo, sin embargo, como algo parecido al tipo de fondo (donde el object
es el tipo superior ). En lisp, el tipo de fondo es NIL
y en Scala es Nothing
.
Habría sido posible diseñar C # sin ningún valor nulo, pero luego habría que encontrar una solución aceptable para los usos que la gente normalmente tiene para unitialized-value
null
, como unitialized-value
, not-found
, default-value
, undefined-value
, y None<T>
. Probablemente habría habido menos adopción entre los programadores de C ++ y Java si de todos modos consiguieran hacerlo. Al menos hasta que vieron que los programas C # nunca tenían excepciones de puntero nulo.
- Anulación explícita, aunque eso rara vez es necesario. Tal vez uno puede verlo como una forma de programación defensiva.
- Úselo (o nullable (T) estructura para elementos no nulables) como un indicador para indicar un campo faltante al mapear campos de una fuente de datos (flujo de bytes, tabla de base de datos) a un objeto. Puede ser muy difícil de usar hacer una bandera booleana para cada campo con posibilidad de nulos, y puede ser imposible usar valores centinela como -1 o 0 cuando todos los valores en el rango de ese campo son válidos. Esto es especialmente útil cuando hay muchos campos diferentes.
Si estos son casos de uso o abuso es subjetivo, pero los uso a veces.