Perché un Linq Cast < T > operazione fallita quando ho definito un cast implicito?
Domanda
Ho creato due classi, una delle quali ha un cast implicito tra di loro:
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};
}
}
Quando creo un nuovo elenco di un tipo e provo a trasmettere < T > all'altro, fallisce con InvalidCastException:
List<Class2> items = new List<Class2>{new Class2{Test2 = 9}};
foreach (Class1 item in items.Cast<Class1>())
{
Console.WriteLine(item.Test1);
}
Questo, tuttavia, funziona bene:
foreach (Class1 item in items)
{
Console.WriteLine(item.Test1);
}
Perché il cast implicito non viene chiamato quando si utilizza Cast < T > ;?
Soluzione
Perché, guardando il codice tramite Reflector, Cast non tenta di prendere in considerazione operatori cast impliciti (il codice LINQ Cast è fortemente ottimizzato per casi speciali di ogni tipo, ma nulla in quella direzione) (come molti linguaggi .NET non lo faranno).
Senza riflettere e altre cose, i generici non offrono alcun modo per prendere in considerazione tali cose extra in ogni caso.
EDIT: in generale, strutture più complesse come implicite / esplicite, operatori di uguaglianza ecc. non sono generalmente gestite da strutture generiche come LINQ.
Altri suggerimenti
Puoi anche utilizzarlo per eseguire il cast con le conversioni, se necessario:
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);
}
}
Da http: //adventuresdotnet.blogspot .com / 2010/06 / migliore-più-type-safe-alternative-to.html
Grazie per quello che stavo per usare quel caso esatto da qualche parte. Mi hai risparmiato un sacco di tempo. Come possibile soluzione al tuo problema, puoi utilizzare ConvertAll < > invece, in questo modo:
foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
{
Console.WriteLine(item.Test1);
}
EDIT: o se vuoi essere più esplicito che il cast è implicito, allora funziona anche questo:
foreach (Class1 item in items.ConvertAll<Class1>(i => i))
{
Console.WriteLine(item.Test1);
}
Una soluzione potrebbe essere quella di utilizzare un po 'di linq'ing qui se hai davvero bisogno di questo tipo di conversione:
List items = new List{new Class2{Test2 = 9}}; foreach (Class1 item in (from x in items select (Class1)x)) { Console.WriteLine(item.Test1); }