EDIT: Tengo ahora blogged about this con más detalle.
Mi original (y ahora creo incorrecta) pensamiento: las limitaciones genéricas no son tomados en cuenta durante las fases de inferencia de resolución de sobrecarga y tipo - que sólo son utilizados para validar el resultado de la resolución de sobrecarga.
EDITAR: Bien, después de un lote de dar la vuelta en esto, creo que estoy allí. Básicamente mi primer pensamiento fue casi correcto.
Las restricciones de tipo genérico solo actúan para eliminar los métodos de un conjunto de candidatos en un conjunto limitado de circunstancias muy ... en particular, solo cuando el tipo de un parámetro en sí es genérico; no solo un parámetro de tipo, sino un tipo genérico que usa un parámetro de tipo genérico. En ese punto, son las restricciones en los parámetros de tipo del tipo genérico los que se validan, no las restricciones en los parámetros de tipo del método genérico al que se llama.
Por ejemplo:
// Constraint won't be considered when building the candidate set
void Foo<T>(T value) where T : struct
// The constraint *we express* won't be considered when building the candidate
// set, but then constraint on Nullable<T> will
void Foo<T>(Nullable<T> value) where T : struct
Así que si se intenta llamar Foo<object>(null)
el método anterior no será parte del conjunto de candidatos, porque Nullable<object> value
no satisface las restricciones de Nullable<T>
. Si hay otros métodos aplicables, la llamada aún podría tener éxito.
Ahora bien, en el caso anterior, las limitaciones son exactamente lo mismo ... pero no es necesario. Por ejemplo, considere:
class Factory<TItem> where TItem : new()
void Foo<T>(Factory<T> factory) where T : struct
Si se intenta llamar Foo<object>(null)
, el método seguirá siendo parte del conjunto de candidatos - porque cuando TItem
es object
, la restricción expresa en Factory<TItem>
todavía mantiene, y que es lo que está controlada al construir el conjunto de candidatos. Si esto resulta ser el mejor método, entonces falla la validación posterior, cerca del extremo de 7.6.5.1:
Si el mejor método es un método genérico, los argumentos de tipo (suministrado o inferida) se comparan con las restricciones (§4.4.4) declaradas en el método genérico. Si cualquier argumento de tipo no satisface la (s) restricción (es) correspondiente (s) en el parámetro de tipo, se produce un error de tiempo de enlace.
Eric's blog post contiene más detalles sobre esto.
¡Neat find! Pero, ¿cuál es tu pregunta? Una solución? –
Buena pregunta. Pensé que tenía una respuesta simple, pero resultó que no. Espero que no te importe que mi "respuesta" sea más una exploración de lo que está sucediendo que una respuesta en sí misma. –
Gracias por sus comentarios. Eamon - lo siento, mi pregunta no es tan clara - es realmente por qué el compilador no puede determinar el mejor método para usar. Después de leer los comentarios y preguntas, y el enlace proporcionado por LukeH, es porque el compilador no tiene en cuenta las restricciones de tipo al determinar el mejor método para usar. –