代码之家  ›  专栏  ›  技术社区  ›  Coding Flow

linq.cast()扩展方法失败,但(类型)对象起作用

  •  16
  • Coding Flow  · 技术社区  · 15 年前

    为了在一些LINQ到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 回复  |  直到 15 年前
        1
  •  23
  •   LBushkin    15 年前

    这个 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是否存在于 SomeType OtherType -它不能通过类型的引用应用 object . 尝试运行上述代码将在运行时失败,报告如下内容:

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

    Cast<>() 只能执行表示保留转换…这就是为什么你不能用它来应用用户定义的转换。

    埃里克·利珀特有一篇关于 behavior of the cast operator in C# -总是值得一读的。

        2
  •  2
  •   tfish    12 年前

    如果对LINQ程序集进行反编译,则会得到类似于以下内容的代码。前面的答案是正确的,最终转换是从“object”转换为目标类型,对于自定义类型,这将始终失败。

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

    四通

        3
  •  0
  •   iQueue    9 年前

    对于那些在这个问题上寻求解决方法的人…

    Dim res = arrayOfStrings.Select(Function(__) CType( __, YourType ))
    

    不确定C的确切语义,但我相信这很容易。