问题 将List 转换为List


以下代码有效:

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  - 有人知道为什么会这样吗?

UPDATE 

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

7067
2017-09-01 11:51


起源

怎么样的 tblStocks 界定? - Daniel A. White
只是一个想法,不确定这个: repository.Single(id).tblStocks 返回一个数组或列表 JsonStock,所以当你试图施展为 JsonStock 抱怨...... - Marco
@Marco - 不,它不应该抱怨。 - Daniel A. White
tblStock和JsonStock之间有什么关系? - Strillo
假设tblStocks是一个IEnumerable的JsonStock,你的代码应该可行。那么“tblStocks”是什么?我假设还有继承的“JsonStock”类的对象,因为这会导致强制转换异常。 - UrbanEsc


答案:


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)。


6
2017-09-01 12:15



+1表示最完整 - UrbanEsc


隐式和显式转换运算符 被Cast忽略了。在你的情况下,这意味着

 public static explicit operator JsonStock(tblStock stock)

如果被Cast忽略,则它们在foreach情况下不会被忽略


2
2017-09-01 12:16



谁说的?如果那是真的 Enumerable.Cast<T>() 完全没有任何意义。 msdn.microsoft.com/en-us/library/bb341406.aspx 不包含任何信息来支持您的声明。 - VVS
@VVS:你不明白的目的 Enumerable.Cast<T>()。输入是非通用的可枚举。结果是通用的可枚举。这个扩展方法的全部目的是从非通用的可枚举中创建一个强类型的可枚举,你知道对象的类型。有关详细信息,请参阅我的回答 - Daniel Hilgarth
@VVS如果仔细阅读,链接确实包含支持我的声明的信息,我的答案中的链接也是如此。您提供的链接谈论 投 上面的运营商是一个 转变 运营商。使用两者的语法相同(SomeType),但不会使它们相同。所以我真的没有得到你的downvote - Rune FS
好吧,看起来你们两个都是对的。撤销了我的-1。 - VVS


而不是使用Cast,考虑使用OfType。在Cast中,如果您正在处理的项目不是destired类型,您将获得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();

1
2017-09-01 12:11





啊,显式运算符重载的奇迹。

因此,要解决您的问题,您可能需要事先调用Select。

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

但是我会说这个运算符重载是你应该摆脱的东西。考虑用类似实现的复制构造函数替换它

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

1
2017-09-01 12:18



+1感谢您的解决方案:P - Jimbo


  • tblStocks.Cast<JsonStock>() 执行演员表演。
  • (JsonStock) item 执行演员表演 或应用自定义转换

由于tblStock是一个LINQ to SQL类,而JsonStock是由您创建的自定义类,因此没有一个是另一个的子类型。因此,你不能在两者之间施放。

要解决此问题,您可以使用 Select LINQ的子句并手动转换元素:

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

1
2017-09-01 12:15