Сбой метода расширения LINQ .Cast (), но (тип) объект работает - PullRequest
16 голосов
/ 12 мая 2010

Для преобразования между некоторыми объектами 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 ]

24 голосов
/ 12 мая 2010

Метод расширения 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<>() может выполнять только преобразования, сохраняющие представление ... поэтому вы не можете использовать его для применения пользовательских преобразований.

У Эрика Липперта есть отличная статья о поведении оператора приведения в C # - всегда стоящее чтение.

2 голосов
/ 28 августа 2013

Если вы декомпилируете сборку 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

0 голосов
/ 25 января 2016

Для тех, кто задал этот вопрос, ищет обходной путь ...

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

Не уверен, что точная семантика с C #, но я уверен, что это довольно просто.

...