2009-08-26 19 views
9

Este parece ser un error para mí ...C# Propiedades automáticas: ¿sigue siendo nulo después de + =?

acepto que las propiedades automáticas, que se define como tal:

public decimal? Total { get; set; } 

será nula cuando se accede a ellos en primer lugar. No se han inicializado, por lo que son nulos.

Pero, incluso después de establecer su valor a través de + =, este decimal? sigue siendo nulo. Así que después de:

Total += 8; 

Total sigue siendo nulo. ¿Cómo puede ser esto correcto? Entiendo que está haciendo un (null + 8), pero parece extraño que no recoge que significa que sólo se debe establecer en 8 ...

Adiciones:

me hizo la "nula + 8 "punto en mi pregunta, pero tenga en cuenta que funciona con cadenas. Por lo tanto, null + "hola" bien, y devuelve "hola". Por lo tanto, detrás de escena, está inicializando la cadena a un objeto de cadena con el valor de "hola". El comportamiento debe ser el mismo para los otros tipos, IMO. Puede ser porque una cadena puede aceptar un valor nulo como valor, pero aún así, una cadena nula no es un objeto inicializado, ¿correcto?

tal vez es sólo porque una cadena no es un anulable ...

+7

"No han sido inicializado, así que por supuesto son nulas." Este es el quid de tu confusión. Las propiedades se asignan inicialmente de forma automática, en este caso, a nulo. Estás razonando desde una falsedad: que la propiedad no está asignada. * La propiedad se asignó inicialmente. * No existe una "propiedad no asignada" en C#. –

+1

distinción interesante. También es interesante que haya miles de ejemplos de personas que se refieren a valores "inicializados a nulos" como "no inicializados". Entonces quizás es un error común. Una cosa que me produce curiosidad: si tenemos este problema en el que no queremos hacer "null + 8 = 8" o "null && true == true", ¿por qué una excepción no se lanza cuando estos tipos de cosas están hechas? Parece que eso podría evitar algunos errores difíciles de depurar. –

Respuesta

30
public decimal? Total { get; set; } 

Piense en null como "valor desconocido". Si tiene una cantidad desconocida de y agrega 8 más, ¿cuántos tiene ahora?

Respuesta: desconocido.

Operaciones de variables anulables

Hay son los casos en que las operaciones en desconocidos valores que dan conocibles resultados.

public bool? State { get; set; } 

Las siguientes declaraciones tienen conocibles soluciones a pesar de que contienen desconocidos valores:

State = null; 
nextState = State & false;   // always equals false 
nextState = State & true;   // still unknown (null) 

nextState = State | true;   // always true 
nextState = State | false;   // still unknown (null) 

ver el patrón?

Por supuesto, si deseaTotal a ser equivalente (igual) a 0 cuando es null, puede utilizar la operador coalescente nula y escribir algo como esto:

Total = (Total ?? 0) + 8; 

que la voluntad utilizar el valor de Total en su ecuación menos es null, en cuyo caso se utilizará el valor 0.

+0

Sí, supongo que esto tiene sentido. Solo parece funky. :) –

+0

Ah, y una buena llamada sobre el operador coalescente. –

+0

'Total = (Total? 0) + 8;' puede reescribirse a 'Total = Total.GetValueOrDefault (0) + 8;' en .NET versión 4.5+ –

6
Null + 8 = Null 

Usted tendrá que establecer con cero antes.

+1

Sí, sé que esa es la solución, solo creo que es tonto. :) –

+0

¿por qué es tonto? null! = 0 –

+0

Porque es contrario a la intuición, al menos para mí. Si fuera mi compilador, lo habría hecho la suposición (especialmente con algo como una propiedad _automatic_) que si tiene un valor no inicializado y se añade algo a ella, sólo se recogería el valor añadido. Pero, tal vez hay algunos casos en los que este tipo de suposición causaría problemas, quién sabe. –

5

null significa valor desconocido,

unknown value + known value = still unknown value 
+0

Entiendo lo que es un nulo, pero me parece que sería una suposición segura de que nulo + 8 sería igual a 8. Pero, supongo que estoy equivocado. :) –

+0

Estás equivocado :) Si 'null' era igual a' 0' ¿cuál sería el punto de tener un 'nulo'? Tenga en cuenta que si define su propiedad como un tipo que no admite nulos (eliminar el signo '?') Se le asignará el valor predeterminado para el tipo decimal, que AFAIK es 0 y podrá usar su código '+ = 8'. – RaYell

+0

Haha - :) Sí, he notado el valor predeterminado con autopropósitos. No digo que nulo sea igual a cero, solo que si tienes un valor inicializado y lo agregas a un valor nulo, tiene sentido para mí que el campo simplemente recoja el valor inicializado. –

0

para ajustar el valor del total es sólo

Total = 8; 

Yo recomendaría leer sobre Nullable Types para entender cómo funcionan. Puede verificar si la propiedad tiene un valor usando HasValue.

De MSDN:

Operadores

Los predefinidos unarios y binarios operadores y cualquier operadores definidos por el usuario que existen para los tipos de valor también puede ser utilizada por tipos anulables. Estos operadores producen un valor nulo si los operandos son nulos; de lo contrario, el operador usa el valor contenido para calcular el resultado.Por ejemplo:

int? a = 10; 
int? b = null; 

a++;   // Increment by 1, now a is 11. 
a = a * 10; // Multiply by 10, now a is 110. 
a = a + b; // Add b, now a is null. 
+0

Gracias. Utilicé bastante los tipos de nullable, y me he encontrado con este problema con la inicialización automática de propiedades bastante, pero nunca me molesté en preguntar por qué. Supongo que tiene sentido, aunque no sé si lo hubiera hecho de esa manera ... –

+0

Hay una buena sección sobre Tipos Nullable en C# en profundidad, entre otros detalles interesantes de C# 3, pero también una poco C# 1 y un poco más en C# 2. Un gran libro de hecho. –

+0

La idea general de los tipos que aceptan nulos es que puedes asignar valores nulos a los tipos de valores :) –

2

De MSDN:

Al realizar comparaciones con tipos anulables, si el valor de uno de los tipos anulables es nula y la otro no es, todo las comparaciones evalúan como falso, excepto para! = (no igual). Es es importante no asumir que porque una comparación particular devuelve falso, el caso opuesto devuelve verdadero.

Por lo tanto, funciona según lo previsto.

3

Aquí hay una sola línea para inicializar en la primera llamada y se incrementará después:

public void InitializeOrIncrement(decimal value) 
    { 
     // if Total is null then initialize, otherwise increment 
     Total = (Total == null) ? value : Total + value; 
    } 

    public decimal? Total { get; set; } 
0

Null i no es lo mismo que cero. Zero más ocho es ocho ... ¿pero nulo más ocho? Siempre nulo. Al igual que el infinito y todo lo demás sigue siendo infinito, no está definido.

Encontrarás que esto es universalmente cierto para null. Cada base de datos (al menos con la que alguna vez he trabajado) le dará el mismo resultado.

+0

El infinito + x = infinito es una buena manera de poner eso. –

0

decimal público?Total {obtener; conjunto; }

¿Podría algo así como este trabajo? Algún tipo de iniciación automática si el valor aún no está establecido.

public decimal? Total 
{ 
    get { return this.totalValue;} 
    set 
    { 
    if(totalValue == null) { this.totalValue = 0;} 
    this.totalValue = value; 
    } 
} 

private decimal? totalValue; 
+0

... pero si no está utilizando propiedades implementadas automáticamente, ¿por qué no inicializar su campo de respaldo como parte de su declaración? 'decimal privado? totalValue = 0; ' – STW

+0

Sí, seamos sinceros, la única razón por la que estoy usando propiedades automáticas es ser flojo al escribir. (¡No mecanografía de objetos, solo digitación de dedos!) Si fuera a dividirlo, simplemente lo predeterminaría a 0. –

+0

Yooder, porque es posible que no quiera que el valor sea 0, puede desear que sea nulo ... Robert, no, en realidad, si alguien establece Total en nulo, se establecerá en 0 y luego se restablecerá a nulo en este caso, ya que 'valor' sería nulo. 0 solo se usa como un iniciador perezoso. – Ian

1

Sé que tiene sentido hacer

public decimal? Total { get; set; } 

Total = (Total ?? 0) + 8; 

pero wouldnt que sólo sea más fácil de hacer:

public decimal Total { get; set; } 

valor inicial de total es de 0

+0

Sí, esto es en realidad a lo que terminé cambiando mi código. Para un total acumulado, realmente no tiene sentido para el total para siempre por nulo realmente, si lo piensas. Tiene sentido que los elementos que se agregan sean potencialmente nulos, pero el total probablemente siempre sea> = 0. Sin embargo, una discusión interesante. –

1

Como otra la gente ha señalado, nulo no es igual a cero. Aunque puede parecer más conveniente que un entero nulo sea predeterminado a cero a largo plazo, es probable que produzca resultados extraños que puede no detectar hasta que sea demasiado tarde.

Como un ejemplo rápido, dicen que uno de tus feeds de datos falla y rellena el conjunto de resultados con valores nulos. Sus cálculos tratarán los nulos como ceros y continúan produciendo los resultados. Debido a que los números aún están apareciendo, aunque probablemente estén equivocados, es posible que nunca notes que algo ha ido muy mal.

Cuestiones relacionadas