Список кастингов <x>в список <y> - PullRequest
11 голосов
/ 01 сентября 2011

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

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;
    }
}

Ответы [ 5 ]

6 голосов
/ 01 сентября 2011

Cast используется для преобразования неуниверсальной коллекции в общую, т.е. выполняет операцию распаковки.Его нельзя использовать так, как вы хотите.
Когда вы посмотрите на реализацию 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 голосов
/ 01 сентября 2011

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

 public static explicit operator JsonStock(tblStock stock)

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

1 голос
/ 01 сентября 2011

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

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

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

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

class JsonStock
{
     public JsonStock(tblStock other)
     {
          // copy values here
     }
}
1 голос
/ 01 сентября 2011
  • tblStocks.Cast<JsonStock>() выполняет приведение.
  • (JsonStock) item выполняет приведение или применяет пользовательское преобразование .

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

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

 List<JsonStock> stock = repository.Single(id).tblStocks
     .Select(item => (JsonStock) item).ToList();
1 голос
/ 01 сентября 2011

Вместо использования Cast рассмотрите возможность использования OfType. В Cast, если обрабатываемый вами элемент не является устаревшим типом, вы получите исключение 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...