Nano Hash - криптовалюты, майнинг, программирование

Повышение приведения с помощью параметра универсального типа

Можно ли «преобразовать» общий класс, основанный на T, в общий класс, основанный на чем-то более общем, чем T?

Например, предположим, что у меня есть класс с именем Derived, который наследуется от класса с именем Base. Могу ли я когда-нибудь сделать что-то вроде этого:

List<Derived> der = new List<Derived>();
List<Base> bas = (List<Base>) der;

Или, используя интерфейсы, можно ли сделать что-то вроде этого:

List<MyClonableType> specific = new List<MyClonableType>();
List<IClonable> general = (List<IClonable>)specific;

Как написано здесь, каждый из этих примеров завершается с ошибкой InvalidCastException. Вопрос, о котором мы спорим, заключается в том, действительно ли это невозможно, или это просто синтаксическая ошибка, которую можно было бы исправить, если бы мы знали, как это сделать.

09.02.2010

  • Java имеет <? extends X> для этого типа конструкции, я был бы удивлен, что C# не имеет эквивалента. 09.02.2010
  • C# имеет общие ограничения (ключевое слово where) для того же, что и extends, но я не уверен, что это то, что нужно Auraseer. Он хочет на самом деле использовать дисперсию в коллекции, исходя из ее внешнего вида. 09.02.2010
  • @Romain, это приведение недопустимо в C#, но вы можете определить такой метод, как void Process<T>(List<T> list) where T: Base {...} 09.02.2010
  • @finnw: Понятно ... Думаю, ограничение where охватывает типичные варианты использования. Однако синтаксис немного тяжеловат (но более гибкий, чем в Java). 09.02.2010

Ответы:


1

C# 4.0 будет иметь эту функцию.

Он будет включен на интерфейсах и делегатах, которые придерживаются определенных правил. List<T> не будет поддерживаться, так как это конкретный класс. IList<T> также не будет поддерживаться, так как его методы используют T в позициях in и out.

09.02.2010
  • Эта ссылка также говорит мне точно, что это приведение не разрешено до версии 4.0. Это именно то, что я хотел знать. 09.02.2010
  • Даже в .NET 4.0 это не будет применяться к List‹T›. 09.02.2010
  • Хорошая точка зрения. Вариантность поддерживается только для интерфейсов и делегатов. 09.02.2010
  • C# 4.0 не будет иметь этой функции для List<T>. Это небезопасно по своей сути. 09.02.2010
  • Не будет этой функции и в интерфейсе IList<T> 10.02.2010

  • 2

    Этот

    List<Derived> der = new List<Derived>(); 
    List<Base> bas = (List<Base>)der;
    

    невозможно и никогда не должно быть возможно. Что здесь происходит:

    Base b = new Base();
    bas.Add(b);
    

    Кабум! вот что происходит. Если бы вышеизложенное было законным, bas просто ссылался бы на der, а der не мог бы добавлять экземпляры Base, что и пытался бы сделать Add. (Для конкретности представьте Base как Animal, а Derived как Cat; вы не можете преобразовать List<Cat> в List<Animal>, потому что тогда вы можете добавить экземпляр Dog в список приведения, который потерпит неудачу, потому что это действительно List<Cat>.)

    По аналогичным причинам

    List<MyClonableType> specific = new List<MyClonableType>();  
    List<IClonable> general = (List<IClonable>)specific;  
    

    никогда не должно быть возможным.

    В C# 4.0 некоторые из этих проблем будут решается с помощью понятия ковариантности и контравариантности. Например, в C# 4.0 это будет допустимо:

    List<Derived> der = new List<Derived>();
    IEnumerable<Base> bas = der;
    

    Это потому, что IEnumerable<Base> выдает только экземпляры Base, а поскольку все Derived являются Base, это нормально. Другими словами, IEnumerable<Base> говорит: «Я знаю, как бросать в вас экземпляры Base», а List<Derived> говорит: «Я знаю, как бросать в вас экземпляры Derived». Но поскольку все Derived являются Base, это означает, что List<Derived> также знает, как бросать в вас экземпляры Base. Следовательно, его можно назначить экземпляру IEnumerable<Base>. Это то, что возможно в C# 4.0. Это пример ковариации.

    Я должен подчеркнуть, что для таких типов, как List<T>, у которых есть методы, которые одновременно потребляют Ts и выплевывают Ts, это невозможно.

    09.02.2010

    3

    Есть хорошее расширение LINQ:

    der.ToList<Base>();
    
    09.02.2010
  • Я считаю, что этот метод создает совершенно новую коллекцию. Это может быть полезно, если у вас есть Linq, но это не то же самое, что приведение типов. 09.02.2010
  • Это правда, что вы можете специально работать с типами IEnumberable‹T› таким образом, но это не фактическое приведение, как задается вопрос. В этом случае метод ToList‹Base›() создает новый список ‹Base› и заполняет его путем приведения каждого элемента из оригинала. 09.02.2010
  • Если вы собираетесь читать только список (что является единственным случаем, когда приведение имеет смысл), по-видимому, не имеет значения, читаете ли вы копию или оригинал. 09.02.2010
  • Финн, это имеет значение. Если я копирую объект и сохраняю ссылку на копию, то оригинал изменяется каким-то другим фрагментом кода, и я никогда не узнаю об этом изменении. Кроме того, простое преобразование может быть очень дорогостоящим, в то время как приведение почти бесплатно. 09.02.2010
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..