Список каста <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
}
}