2010-02-01 16 views
45

Duplicar posibles:
C# okay with comparing value types to nullGuid == null no se debe permitir por el compilador

El comportamiento se describe a continuación es específico de .NET-3,5 solamente

Hola,

Acabo de encontrar el comportamiento más sorprendente en el compilador de C#;

Tengo el siguiente código:

Guid g1 = Guid.Empty; 
bool b1= (g1 == null); 

Bueno, Guid no es anulable por lo tanto, nunca puede ser igual a null. La comparación que estoy haciendo en la línea 2 siempre devuelve falso.

Si hace lo mismo para un entero, el compilador emite una advertencia diciendo que el resultado siempre será falsa:

int x=0; 
bool b2= (x==null); 

Mi pregunta es: ¿Por qué permite que el compilador se compara un Guid nulo?
De acuerdo con mi conocimiento, ya sabe que el resultado siempre es falso.
¿La conversión integrada está hecha de tal manera que el compilador asume que null es un valor posible?
¿Me falta algo aquí?

Gracias

+1

Posible duplicado: http://stackoverflow.com/questions/1972262/c-okay-with-comparing-value-types-to-null – BFree

+8

No es en realidad un duplicado. La pregunta de Luis se trata de por qué el compilador no emite una advertencia en caso de comparar una estructura con nulo, y lo hace al comparar un tipo de valor. –

+4

No estoy de acuerdo con que se trate de un duplicado ... –

Respuesta

74

La marca es correcta. Los tipos de valor que definen sus propios operadores de igualdad automáticamente también definen las versiones mejoradas y anulables, de forma gratuita. El operador de igualdad anulable que toma dos guiones con nulos es aplicable en esta situación, se llamará y siempre devolverá falso.

En C# 2, esto produjo una advertencia, pero por alguna razón, esto dejó de producir una advertencia para guid-to-null, pero continúa produciendo una advertencia para int-to-null. No sé por qué; No he tenido tiempo de investigar todavía.

Pido disculpas por el error; Probablemente arruiné una de las rutas del código de detección de advertencia cuando reescribí la lógica nullable en C# 3. La adición de árboles de expresión al lenguaje cambió principalmente el orden en que se realizan las operaciones aritméticas anulables; Cometí numerosos errores al mover ese código. Es un código complicado.

+31

+1 Qué respuesta sincera. ;-) –

+0

¿Hay alguna razón por la cual el comportamiento de los Guids y las cadenas sea tan diferente? ¿Simplemente implementado en diferentes iteraciones en lugar de tener la misma implementación que una cadena no puede ser nula y en su lugar requiere una cadena anulable en su lugar y nunca se consideró que valiera la pena el cambio? –

+0

@Chris: este problema solo afecta a los tipos de valor. Las cadenas son tipos de referencia. 'null' es (y siempre ha sido) perfectamente válido para' string'. –

13

La comparación es válida porque el compilador convierte el Guid a un Nullable<Guid> y entonces tiene sentido.

Hay un informe de error en la advertencia que no se emite here.

Ver herehere para una explicación más completa de Eric Lippert.

+0

Lo siento, esto no tiene sentido. ¿Por qué no convierte automáticamente un int a Nullable ? –

1

En realidad hay un caso cuando Guild == null devolverá true.

Sin embargo, es un poco difícil de explicar.

En los marcos de mapeo ORM (openAccess por ejemplo) cuando se tiene un campo GUID que tendrá un valor por defecto de Guid.Empty por supuesto que es posible tener el escenario barbecho:

  • se agrega una nueva Guid field + a Property
  • Actualiza el viejo esquema de la base de datos ... en este caso, todos los valores serán NULL en la base de datos.
  • Si llena un objeto que tenga esta columna nula de tipo Gremio, por supuesto, el Objeto obtendrá un valor Guid.Empty SIN EMBARGO, si utiliza una consulta LINQ ... en la consulta LINQ parece que el Guid aún no está poblado por lo que necesita usar == nulo. Tal vez es un error, pero esta es la forma en que es.

En pocas palabras (usando OpenAccess pero probablemente no sólo):.

elemento var = GetItems() Donde (i => i.SomeGuidField == null); funcionará y obtendrá los elementos con null guid esto es después de una actualización de esquema. . item.First() SomeGuidField volverá vacíos Guid

artículo var = GetItems() Donde (i => i.SomeGuidField == Guid.Empty).; no funcionará incluso si después de la población del elemento será Guid.Empty y devolverá el resultado vacío.

+2

Eso no es en realidad 'Guid == null' devuelve true; es un motor de consultas que interpreta los árboles de expresión de forma diferente que C#. – SLaks

0

Por supuesto, esto no es solo un problema para Guid. El mismo comportamiento se observa con cualquier tipo de struct que no sea un tipo predefinido de C#, siempre que el struct sobrecargue operator == de la forma habitual. Otros ejemplos en el marco incluyen DateTime y TimeSpan.

Esto merece una advertencia en tiempo de compilación ya que, aunque técnicamente legal debido al operador levantado, esta no es una comparación útil ya que siempre da false. Como tal, es una indicación de un error del programador.

Como dijo Eric Lippert en su respuesta, la advertencia en tiempo de compilación existía con el compilador de Visual C# 2.0. En las versiones 3.0 a 5.0, la advertencia se omitió accidentalmente (para estos tipos "definidos por el usuario" struct, pero no para tipos de valores predefinidos como int, y no para tipos de enumeración).

Desde C# 6.0 (basado en Roslyn), el compilador detecta este problema de código una vez más. Sin embargo, debido a la compatibilidad con versiones anteriores (?!), la advertencia no se emite a menos que compile su código con la llamada característica estricta.

Para habilitar estricta cuando se utiliza un archivo .csproj (caso más habitual), descargar el proyecto de Visual Studio, editar el archivo, insertar el elemento XML:

<Features>strict</Features> 

en cada <PropertyGroup> (generalmente existirá más de uno) del archivo .csproj. A continuación, recibe la advertencia (se puede "promocionar" a un error si utiliza las advertencias de Treat como errores).

Si no puede editar el .csproj y si se llama msbuild.exe desde la línea de comandos para compilar, utilice el interruptor:

/p:Features=strict 

a msbuild.exe.

Si no se utiliza .csproj archivos porque se compila directamente con csc.exe (el compilador de C#), utilice el interruptor:

/features:strict 

a csc.exe en la línea de comandos.

Cuestiones relacionadas