Подтвердить что ты не робот

Метод расширения LINQ.Cast() не работает, но (тип) работает

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

4b9b3361

Ответ 1

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

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

Ответ 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

Ответ 3

Для тех, кто сталкивается с этим вопросом в поисках обходного пути...

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

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