2011-09-29 25 views
10

La definición de Nullable<T> es:¿Por qué no puedo escribir Nullable <Nullable <int>>?

[SerializableAttribute] 
public struct Nullable<T> where T : struct, new() 

La restricción where T : struct implica que T sólo puede haber un tipo de valor. Así que muy bien entendido que no puedo escribir:

Nullable<string> a; //error. makes sense to me 

Debido string es un tipo de referencia, no es un tipo de valor. Pero realmente no entiendo por qué no puedo escribir

Nullable<Nullable<int>> b; //error. but why? 

¿Por qué no está permitido? Después de todo, Nullable<int> es un tipo de valor y, por lo tanto, puede ser un argumento de tipo Nullablle<T>.

Cuando he recopilado en Ideone, se da este error (ideone):

CS0453 error: '? Int' El tipo debe ser un tipo de valor no anulable con el fin de utilizarlo como parámetro de tipo de 'T' en el tipo genérico o método 'System.Nullable' Compilación falló: 1 error (s), 0 advertencias

+0

¿Cuál es el error? – asawyer

+2

Lo siento, mi respuesta es incorrecta. La sentencia 'new Nullable ();' compila (lo que da como resultado un 'int?' Con un valor de nulo), aunque el constructor predeterminado no está documentado. – BoltClock

+0

Y sí, la respuesta está en el error que debe obtener cuando intenta compilar su código. – BoltClock

Respuesta

5

Desde la sección 4.1.10 de la especificación del lenguaje C#:

Un tipo de valor no anulable inversa es cualquier tipo de valor que no sea System.Nullable<T> y su forma abreviada T? (para cualquier T), más cualquier parámetro de tipo que esté restringido a ser un tipo de valor que no admite nulos (es decir, cualquier parámetro de tipo con una restricción struct). El tipo System.Nullable<T> especifica la restricción de tipo de valor para T (§10.1.5), lo que significa que el tipo subyacente de un tipo que admite nulos puede ser cualquier tipo de valor que no admite nulos. El tipo subyacente de un tipo que admite nulos no puede ser un tipo anulable o un tipo de referencia. Por ejemplo, int?? y string? son tipos no válidos.

9

Debido a que es en el C# spec (sección 4.4.4):

Si la restricción es la restricción de tipo de valor (struct), el tipo a debe satisfacer una de las siguientes:

  • a es un tipo struct o enum type, pero no es un tipo que admite nulo. Tenga en cuenta que System.ValueType y System.Enum son tipos de referencia que no satisfacen esta restricción.
  • A es un parámetro de tipo que tiene la restricción de tipo de valor (§10.1.5).
+0

Amplíe la cita de la especificación. No entendí completamente eso. Soy nuevo en C#. – Nawaz

+0

La restricción de tipo genérico 'struct' que aplica a las clases está _specified_ como 'todos los tipos de valor y enum aparte de' Nullable '', específicamente para detener esta circularidad. – thecoop

+0

@thecoop: No es una singularidad. Si no fuera por la restricción 'struct' en el parámetro de tipo' Nullable', podría ser útil tener un 'Dictionary ' incluir un método 'Nullable ' TryGetValue (TKey) 'sin tener que usar un parámetro' out'. Dado 'Dictionary > myDict', después de' var it = myDict.TryGetValue ("Fred"); 'si' it.HasValue' era falso, eso significaría que no se encontró ninguna clave; si 'it.HasValue' era verdadero pero' it.Value.HasValue' era falso, eso significaría que se almacenó un valor nulo para la clave "Fred". La verdadera dificultad radica en la decisión de MS de ... – supercat

3

De §10.1.5 de la especificación C# 4:

El tipo de valor de restricción especifica que un argumento de tipo utilizado para el parámetro de tipo debe ser un tipo de valor no anulable. Todos los tipos de estructuras no en nula, tipos enum y parámetros de tipo que tienen la restricción de tipo de valor satisfacen esta restricción. Tenga en cuenta que aunque clasificado como un tipo de valor, un tipo anulable (§4.1.10) no satisface la restricción de tipo de valor. Un parámetro de tipo que tenga la restricción de tipo de valor tampoco puede tener la restricción de constructor.

1

Como han dicho otros, la especificación prohíbe esto.

de excavación más profunda, vale la pena darse cuenta de que puede hacer su propia estructura que permite que este patrón:

struct Nestable<T> where T : struct { /* ... */ } 

new Nestable<Nestable<int>>(); // This works just fine 

La prohibición de nullables anidadas no se puede expresar mediante el sistema de tipos disponibles para usted y para mí. Solo se aplica por un caso especial en el compilador (CS0453).


Aparte: La restricción new() se muestra en la pregunta en realidad no existe en System.Nullable<T>. new() restricciones están prohibidas cuando se usa la restricción struct.

CS0451: El 'nuevo()' restricción no se puede utilizar con la restricción 'struct'

Todo el apoyo estructuras predeterminado de inicialización de todos modos.

+0

De acuerdo con los documentos, ya no existe la restricción 'new()': https://referencesource.microsoft.com/#mscorlib/system/nullable.cs – series0ne

1

Esto no es exactamente una respuesta, sino solo algo para pensar.

Ronda 1

Nullable<Nullable<int>> a;

CS0453 de error: El tipo 'int?' debe ser un tipo de valor no anulable con el fin de utilizarlo como parámetro de 'T' en el tipo genérico o método 'Anulable'

Intellisense insinúa ... El nombre se puede simplificar


Ronda 2

Nullable<int?> a;

error CS0453: El tipo 'int?' debe ser un tipo de valor no anulable con el fin de utilizarlo como parámetro de 'T' en el tipo genérico o método 'Anulable'

Intellisense insinúa ... El nombre se puede simplificar


Ronda 3

int?? a;

error CS1519: token no válido '??'en clase, estructura o declaración de miembro de interfaz

error CS1525: término de expresión no válido' ?? '


Conclusión

int? es esencialmente sólo una breve evaluación de mano de Nullable<int>, pero no hay tal cosa como int?? que es la única forma que veo de representar Nullable<Nullable<int>> en taquigrafía . Además, int?? toma prestado el operador nulo-coalescente, así que me alegro de que no sea posible porque parece horrible. Imagine int????????????? a; Qué inútil.

Finalmente, dado que la fuente de referencia para Nullable no genera ninguna restricción para imponer esto, mi conjetura es que esta restricción se incluyó en el CLR como un caso especial cuando se introdujeron tipos de valores nulables en C#.

Cuestiones relacionadas