Почему операция приведения Linq завершается с ошибкой<T> , когда у меня определено неявное приведение?

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

  •  03-07-2019
  •  | 
  •  

Вопрос

Я создал два класса, причем один из них имеет неявное приведение между ними:

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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top