Список каста <x> в список <y>

Работает следующий код:

List<JsonStock> stock = new List<JsonStock>();

foreach(tblStock item in repository.Single(id).tblStocks)                
    stock.Add((JsonStock) item);

Итак, вы, наверное, думаете, что этот код тоже будет работать:

List<JsonStock> stock = repository.Single(id).tblStocks.Cast<JsonStock>().ToList()

Но я получаю сообщение об ошибке Invalid cast operation - кто-нибудь знает, почему это может случиться?

ОБНОВЛЕНИЕ

tblStocks - это список объектов LINQ to SQL, tblStock.
JsonStock - это упрощенная версия класса tblStock и возвращается на веб-страницу как объект JSON.

Для выполнения кастинга был создан следующий оператор:

public partial class tblStock{
    public static explicit operator JsonStock(tblStock stock){
        JsonStock item = new JsonStock
        {
            boxes = stock.boxes,
            boxtype = stock.tblBoxType.name,
            boxtype_id = stock.boxtype_id,
            grade = stock.grade,
            packrate = stock.packrate,
            weight = stock.weight
        };

        return item;
    }
}

Ответ 1

Cast используется для изменения не общего набора в общий, т.е. выполняет операцию unboxing. Его нельзя использовать так, как вы хотите.
Когда вы посмотрите на реализацию Cast и CastIterator, которые он использует, вы увидите, что он принимает объект и передает его указанному типу:

foreach (object current in source)
{
    yield return (TResult)current;
}

Это работает, только если current - это TResult. В этом случае не применяются специальные преобразования.
Это поведение по умолчанию, вы можете проверить его самостоятельно:

double d = 0.0;
object tmp = d;
int i = (int)tmp; // throws the same exception you are getting

То, что вы хотите, лучше всего сделать с помощью простого Select, если tblStocks является общим перечислением:

List<JsonStock> stock = repository.Single(id).tblStocks
                                  .Select(x => (JsonStock)x).ToList();

Или, если tblStocks является неосновным перечислимым, вам нужно объединить Cast и Select:

List<JsonStock> stock = repository.Single(id).tblStocks.Cast<tblStock>()
                                  .Select(x => (JsonStock)x).ToList();

Это сначала распакует объекты в tblStocks в их реальный тип (tblStock), а затем применит его к типу, который вы хотите (JsonStocks).

Ответ 2

неявные и явные операторы преобразования игнорируются Cast. В вашем случае это означает, что

 public static explicit operator JsonStock(tblStock stock)

игнорируется Cast, однако они не игнорируются в случае foreach

Ответ 3

Вместо использования Cast рассмотрите возможность использования OfType. В роли, если элемент, который вы обрабатываете, не является типом, вы получите InvalidCastException. С OfType он будет ловушкой для недействительных литых и только возвращаемых элементов, которые фактически являются типом, который вы ищете.

List<JsonStock> stock = repository.Single(id).tblStocks.OfType<JsonStock>().ToList() 

Если вы вернете пустые списки, я бы заподозрил, что ваш tblStocks на самом деле не возвращает JsonStocks, и вы пытаетесь проецировать какой-то другой тип (tblStock?) в DTO (JsonStock). Если это так, вам нужно использовать Select для проекта в новый тип из базового типа.

List<JsonStock> stock = repository.Single(id).tblStocks
                        .Select(stock => new JsonStock 
                             { 
                               Id = stock.Id,
                               Val1 = stock.Val1,
                               Val2 = stock.Val2,
                               ...
                             }
                         .ToList();

Ответ 4

  • tblStocks.Cast<JsonStock>() выполняет литье.
  • (JsonStock) item выполняет листинг или применяет настраиваемое преобразование.

Так как tblStock - это класс LINQ to SQL, а JsonStock - это созданный вами пользовательский класс, ни один из них не является подтипом другого. Таким образом, вы не можете бросить между ними.

Чтобы исправить это, вы можете использовать предложение Select LINQ и вручную преобразовать элементы:

 List<JsonStock> stock = repository.Single(id).tblStocks
     .Select(item => (JsonStock) item).ToList();

Ответ 5

Ahhh - чудеса явных перегрузок операторов.

Итак, чтобы исправить вашу проблему, вы можете позвонить заранее.

List<JsonStock> stock = repository.Single(id).tblStocks.Select(x => (JsonStock)x).ToList() 

Однако я бы сказал, что эта перегрузка оператора - это то, от чего вы должны избавиться. Рассмотрите возможность замены его конструктором копирования, таким как реализация

class JsonStock
{
     public JsonStock(tblStock other)
     {
          // copy values here
     }
}