whereselectlistiterator wherelistiterator una tipo puede objeto lista implícitamente falta explícita existe convertir conversión compruebe c# generics

c# - wherelistiterator - no se puede convertir un objeto de tipo whereselectlistiterator



No hay conversión de referencia implícita de ''System.Collections.Generic.List<T>'' a ''T'' (3)

class Class1<T> { public virtual void Update(T entity) { Update(new List<T>() { entity }); //It''s failed } public virtual void Update(IEnumerable<T> entities) { } public virtual void Update<TSub>(TSub entity) where TSub : T { } public virtual void Update<TSub>(IEnumerable<TSub> entities) where TSub : T { } }

Tengo un pedazo de código. Pero siempre fallaba.

Si reemplacé la Update(new List<T>() { entity }) por la Update((new List<T>() { entity }).AsEnumerable()) , estará bien.

También estará bien cuando elimine el tercer método Update<TSub>(TSub entity) where TSub : T

¿Puede alguien decirme por qué?


Básicamente, se pregunta por qué el compilador no está creando una IEnumerable<T> implícita de la List<T> a IEnumerable<T> . La razón es que el equipo de C # tomó una decisión de diseño deliberada de que los casos de ambigüedad potencial deben ser resueltos por el programador, no por el compilador. (Tenga en cuenta que el equipo de VB.NET tomó una decisión diferente, de intentar siempre algo sensato que sea coherente con la intención percibida del programador).

Las ventajas en un caso como este son que la sorpresa se minimiza: nada inesperado puede suceder bajo las coberturas; la desventaja es la necesidad ocasional de un código más detallado.


Las restricciones no son parte de la firma, Eric Lippert tiene un gran article sobre este tema.


OK, vamos a pasar esto con cuidado. Tenemos

Update(new List<T>());

Y tres candidatos: tenga en cuenta que solo nos preocupan las firmas de esos candidatos, así que eliminaremos los tipos y restricciones de devolución, que no son parte de la firma :

Update(IEnumerable<T> entities) Update<U>(U entity) Update<V>(IEnumerable<V> entities)

Nuestra primera tarea es hacer inferencia de tipo sobre esos dos últimos candidatos. Si la inferencia falla, entonces no son candidatos aplicables.

Considera el segundo método.

Update<U>(U entity)

Tenemos un argumento de tipo List<T> y un parámetro formal U Por lo tanto inferimos que U es List<T> .

Considere el tercer método:

Update<V>(IEnumerable<V> entities)

Tenemos un argumento de tipo List<T> y un parámetro formal de tipo IEnumerable<V> . List<T> implementa IEnumerable<T> por lo que deducimos que V es T.

OK, entonces nuestra lista de candidatos ahora consiste en:

Update(IEnumerable<T> entities) Update<List<T>>(List<T> entity) Update<T>(IEnumerable<T> entities)

¿Todos estos candidatos son aplicables ? Sí. En cada caso, la List<T> es convertible al tipo de parámetro formal. No podemos eliminar ninguno de ellos todavía.

Ahora que solo tenemos candidatos aplicables, debemos determinar cuál es el mejor .

Podemos eliminar de inmediato el tercero. El tercero y el primero son idénticos en sus listas de parámetros formales. La regla de C # es que cuando tienes dos métodos que son idénticos en sus listas de parámetros formales, y uno de ellos llegó "naturalmente" y uno de ellos llegó a través de la sustitución de tipo, el sustituto pierde.

También podemos eliminar el primero. Claramente, la coincidencia exacta en la segunda es mejor que la coincidencia inexacta en la primera.

Eso deja al segundo como el último hombre en pie. Se gana la lucha de resolución de sobrecarga. Luego, durante la validación final, descubrimos que se viola la restricción: no se garantiza que la List<T> sea ​​una clase derivada de T

Por lo tanto la resolución de sobrecarga falla. Tus argumentos causaron que el mejor método elegido no fuera válido.

Si llamo a Update((new List<T>() { entity }).AsEnumerable()) , estará bien.

Correcto. Pasalo de nuevo. Tres candidatos

Update(IEnumerable<T> entities) Update<U>(U entity) Update<V>(IEnumerable<V> entities)

Tenemos un argumento de tipo IEnumerable<T> , por lo que inferimos que el segundo y el tercero son:

Update(IEnumerable<T> entities) Update<IEnumerable<T>>(IEnumerable<T> entity) Update<T>(IEnumerable<T> entities)

Ahora tenemos tres candidatos aplicables con listas de parámetros idénticos. Los que llegaron en construcción son automáticamente peores que los naturales, por lo que eliminamos el segundo y el tercero, dejando solo el primero. Gana, y no tiene restricciones que violar.

Estará bien también cuando elimines el tercer método

Tu declaración es falsa; Esto producirá el mismo error que el primer escenario. Quitar al tercer candidato no hace que el primer candidato comience a derrotar repentinamente al segundo candidato.