2011-09-01 36 views
11

下面的代码工作:铸造名单<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 - 有谁知道为什么可能发生?

UPDATE

tblStocks是LINQ到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; 
    } 
} 
+3

“tblStocks”的类型是如何定义的? –

+0

只是一个想法,不知道这个:'repository.Single(id).tblStocks'返回一个数组或列表'JsonStock',所以当你试图将其作为'JsonStock'投射时,它会投诉... – Marco

+0

@Marco - no它不应该抱怨。 –

回答

6

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是非通用枚举,你需要结合CastSelect

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

这将首先将tblStocks中的对象解除其实际类型(tblStock),然后将其转换为您想要的类型(JsonStocks)。

+2

对于最完整的 – UrbanEsc

1

而不是使用铸造的,可以考虑使用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(); 
1
  • tblStocks.Cast<JsonStock>()执行演员。
  • (JsonStock) item执行转换或应用自定义转换

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

为了解决这个问题,你可以使用LINQ的Select条款和手动转换的元素:

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

隐性和显性的转换操作符是ignored by Cast。在你的情况这意味着

public static explicit operator JsonStock(tblStock stock) 

由演员忽略它们然而,不是在foreach情况下

+0

说谁?如果那是真的,那么'Enumerable.Cast ()'根本就没有意义。 http://msdn.microsoft.com/en-us/library/bb341406.aspx不包含任何信息来支持您的声明。 – VVS

+0

@VVS:你不明白'Enumerable.Cast ()'的用途。输入是一个非泛型的枚举。结果是一个泛型的枚举。此扩展方法的全部目的是从非泛型枚举中创建强类型枚举,您知道对象的类型。查看我的答案了解更多详情。 –

+0

@VVS如果仔细阅读,链接确实包含信息来支持我的请求,就像我的答案中的链接一样。 您提供的关于_cast_运算符的链接是_conversion_运算符。使用两者的语法是相同的(SomeType),但不会使它们相同。所以我真的不会得到你的低调 –

1

唉唉,明确运算符重载的奇迹忽略。

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

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

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

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

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