LINQ .Cast()扩展方法失败但(类型)对象有效

时间:2010-05-12 13:59:54

标签: c# linq casting extension-methods

要在一些LINQ to SQL对象和DTO之间进行转换,我们在DTO上创建了显式的转换运算符。这样我们就可以做到以下几点:

DTOType MyDTO = (LinqToSQLType)MyLinq2SQLObj;

这很有效。

但是当你尝试使用LINQ .Cast()扩展方法进行强制转换时,它会抛出一个无效的强制转换异常,说不能将类型Linq2SQLType转换为类型为DTOType。即以下不起作用

List<DTO.Name> Names = dbContact.tNames.Cast<DTO.Name>()
                                               .ToList();

但下面的工作正常:

DAL.tName MyDalName = new DAL.tName();
DTO.Name MyDTOName = (DTO.Name)MyDalName;

以下也可以正常使用

List<DTO.Name> Names = dbContact.tNames.Select(name => (DTO.Name)name)
                                               .ToList();

为什么.Cast()扩展方法会抛出无效的强制转换异常?我过去曾经多次使用.Cast()扩展方法,当你将类似基类型的类型转换为派生类型时,它可以正常工作,但是当对象有一个显式的强制转换操作符时,它就会失效。

3 个答案:

答案 0 :(得分:24)

Cast<>扩展方法不应用用户定义的转换。它只能转换为接口或所提供类型的类层次。

用户定义的转换在编译时根据表达式中涉及的静态类型进行标识。它们不能用作运行时转换,因此以下内容是非法的:

public class SomeType
{
  public static implicit operator OtherType(SomeType s) 
  { 
    return new OtherType(); 
  }
}

public class OtherType { }

object x = new SomeType();
OtherType y = (OtherType)x; // will fail at runtime

UDC是否存在从SomeTypeOtherType并不重要 - 它不能通过object类型的引用应用。试图运行上面的代码会在运行时失败,报告如下:

System.InvalidCastException: 
    Unable to cast object of type 'SomeType' to type 'OtherType'

Cast<>()只能执行保留转化的表示...这就是您无法使用它来应用用户定义的转化的原因。

Eric Lippert撰写了一篇关于behavior of the cast operator in C#的精彩文章 - 总是值得一读。

答案 1 :(得分:2)

如果您对Linq程序集进行反编译,则会得到类似以下内容的代码。之前的答案是正确的,最终演员阵容从“对象”到目标类型,对于自定义类型总是失败。

private static IEnumerable<TResult> CastIterator<TResult>( IEnumerable source )
{
    foreach(object current in source)
    {
        yield return (TResult)( (object)current );
    }
    yield break;
}

public static IEnumerable<TResult> DCast<TResult>( this IEnumerable source )
{
    IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
    if(enumerable != null)
    {
        return enumerable;
    }
    if(source == null)
    {
        throw new ArgumentNullException( "source" );
    }
    return CastIterator<TResult>( source );
}

TFish

答案 2 :(得分:0)

对于那些遇到这个问题寻找解决方法的人......

<?php
foreach ($anna_array as $x => $x_value) {
$speler1_prestaties = "<span class=\"white bold\">".str_pad($count1++, 2, "0", STR_PAD_LEFT)."</span> ".$x.": 
<span class=\"orange\">".$x_value." "(".$points .")></span><br />";     
echo $player1_info;
?>

不确定C#的确切语义,但我确定它非常简单。