¿Por qué un Linq Cast < T > ¿falla la operación cuando tengo un molde implícito definido?

StackOverflow https://stackoverflow.com/questions/808725

  •  03-07-2019
  •  | 
  •  

Pregunta

He creado dos clases, una de ellas con un reparto implícito entre ellas:

public class Class1
{
    public int Test1;
}

public class Class2
{
    public int Test2;

    public static implicit operator Class1(Class2 item)
    {
        return new Class1{Test1 = item.Test2};
    }
}

Cuando creo una nueva lista de un tipo e intento emitir < T > al otro, falla con una InvalidCastException:

List<Class2> items = new List<Class2>{new Class2{Test2 = 9}};
foreach (Class1 item in items.Cast<Class1>())
{
    Console.WriteLine(item.Test1);
}

Esto, sin embargo, funciona bien:

foreach (Class1 item in items)
{
    Console.WriteLine(item.Test1);
}

¿Por qué no se llama la conversión implícita al usar Cast < T > ;?

¿Fue útil?

Solución

Porque, mirando el código a través de Reflector, Cast no intenta tomar en cuenta ningún operador de transmisión implícito (el código LINQ Cast está muy optimizado para casos especiales de todo tipo, pero nada en esa dirección) en cuenta (como muchos lenguajes .NET no lo hará).

Sin entrar en la reflexión y otras cosas, los genéricos no ofrecen ninguna forma inmediata de tener en cuenta tales cosas adicionales en cualquier caso.

EDITAR: en general, las instalaciones más complejas como implícitas / explícitas, operadores de igualdad, etc., generalmente no son manejadas por instalaciones genéricas como LINQ.

Otros consejos

También puede usar esto para realizar conversiones con conversiones si es necesario:

public static IEnumerable<TDest> CastAll<TItem, TDest>(this IEnumerable<TItem> items)
{
 var p = Expression.Parameter(typeof(TItem), "i");
 var c = Expression.Convert(p, typeof(TDest));
 var ex = Expression.Lambda<Func<TItem, TDest>>(c, p).Compile();

 foreach (var item in items)
 {
    yield return ex(item);
 }
}

De http: //adventuresdotnet.blogspot .com / 2010/06 / better-more-type-safe-alternative-to.html

Gracias por eso estaba a punto de usar ese caso exacto en alguna parte. Me has ahorrado un montón de tiempo. Como posible solución a su problema, puede usar ConvertAll < > en cambio, así:

foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
{
     Console.WriteLine(item.Test1);
}

EDITAR: o si quieres ser más explícito de que el reparto está implícito, esto también funciona:

foreach (Class1 item in items.ConvertAll<Class1>(i => i))
{
     Console.WriteLine(item.Test1);
}

Una solución podría ser utilizar un poco de linq'ing aquí si realmente necesita este tipo de conversión:

List items = new List{new Class2{Test2 = 9}};
foreach (Class1 item in (from x in items select (Class1)x))
{
    Console.WriteLine(item.Test1);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top