Почему операция приведения Linq завершается с ошибкой<T> , когда у меня определено неявное приведение?
Вопрос
Я создал два класса, причем один из них имеет неявное приведение между ними:
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};
}
}
Когда я создаю новый список одного типа и пытаюсь привести<T> к другому, он завершается с ошибкой InvalidCastException:
List<Class2> items = new List<Class2>{new Class2{Test2 = 9}};
foreach (Class1 item in items.Cast<Class1>())
{
Console.WriteLine(item.Test1);
}
Это, однако, работает нормально:
foreach (Class1 item in items)
{
Console.WriteLine(item.Test1);
}
Почему неявное приведение не вызывается при использовании приведения<T>?
Решение
Потому что, просматривая код через Reflector, Cast не пытается учитывать какие-либо неявные операторы приведения (код приведения LINQ сильно оптимизирован для особых случаев всех видов, но ничего в этом направлении) (как и многие другие .ЧИСТЫЕ языки этого не сделают).
Не вдаваясь в размышления и другие вещи, generics в любом случае не предлагает какого-либо готового способа учета таких дополнительных факторов.
Редактировать:В общем, более сложные средства, такие как неявный / экспликт, операторы равенства и т.д.обычно не обрабатываются универсальными средствами, такими как LINQ.
Другие советы
Вы также можете использовать это для выполнения приведения с преобразованиями, если это необходимо:
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);
}
}
От http://adventuresdotnet.blogspot.com/2010/06/better-more-type-safe-alternative-to.html
Спасибо за это, я как раз собирался где-нибудь использовать именно этот случай.Вы сэкономили мне кучу времени.В качестве возможного решения вашей проблемы вы могли бы использовать ConvertAll<> вместо этого, вот так:
foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
{
Console.WriteLine(item.Test1);
}
Редактировать:или, если вы хотите быть более явным, чтобы приведение было неявным, то это тоже работает:
foreach (Class1 item in items.ConvertAll<Class1>(i => i))
{
Console.WriteLine(item.Test1);
}
Решением могло бы быть использование здесь немного linq'ing, если вам действительно нужно такое преобразование:
List items = new List{new Class2{Test2 = 9}}; foreach (Class1 item in (from x in items select (Class1)x)) { Console.WriteLine(item.Test1); }