Как сделать деконструктор для класса, реализующего IEnumerable

У меня есть класс, реализующий IEnumerable. Он содержит метод GetEnumerator() и закрытый класс, реализующий IEnumerator. Метод Current() этого класса возвращает объект, который является KeyValuePair, т.е. (некоторый код опущен для ясности)

internal sealed class BlockSheet : IEnumerable
{
    public IEnumerator GetEnumerator ()
    {
        return new BlockSheetEnumerator (this);
    }

    private class BlockSheetEnumerator : IEnumerator
    {
        public object Current
        {
            get
            {
                KeyValuePair<Point, Actor> pair = (KeyValuePair<Point, Actor>)this.enumerator.Current;
                return pair;
            }
        }
    }
}

Это отлично работает, если я вызываю следующим образом

foreach (KeyValuePair<Point, Actor> unit in blocksheet)

но если я попытаюсь использовать неявный деконструктор KeyValuePair и напишу

foreach ((Point coordinate, Actor actor) in blocksheet)

то я получаю две ошибки:

Ошибка CS1061: «объект» не содержит определения для «Deconstruct», и не удалось найти доступный метод расширения «Deconstruct», принимающий первый аргумент типа «object» (вам не хватает директивы using или ссылки на сборку?) (CS1061 )

Ошибка CS8129: не найдено подходящего экземпляра или метода расширения «Деконструировать» для типа «объект» с двумя выходными параметрами и возвращаемым типом void. (CS8129)

(Это та же ошибка, что и, например, Где метод Deconstruct структуры KeyValuePair<>?, но я не думаю, что это применимо — см. ниже)

Я бы подумал, что получу деконструктор «на халяву». Я пытался добавить метод Deconstruct как к классу BlockSheet, так и к классу BlockSheetEnumerator, но безрезультатно (и я не чувствую, что это имеет смысл, потому что ни один из классов не деконструируется).

Я ориентируюсь на .NET 5 с C# 9, используя Visual Studio 2019 для Mac версии 8.10.22 (сборка 11). Я, конечно, успешно использовал деконструктор с объектом, который является словарем, чтобы доказать себе, что это не имеет ничего общего с версией языка/.NET.

Вам нужно реализовать IEnumerable<KeyValuePair<Point, Actor>> в дополнение к IEnumerable.

NetMage 17.05.2022 00:00
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
1
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

IEnumerable означает «коллекция Objects». Итак, внутри цикла вы получаете object на каждой итерации, и на самом деле вы пытаетесь деконструировать объект, а не KeyValuePair<TKey, TValue>. И у вас нет подходящего деконструктора для object.

Чтобы использовать деконструкцию, вам нужен явный и конкретный тип. Для этого вы можете:

  • реализовать IEnumerable<KeyValuePair<Point, Actor>>/IEnumerator<KeyValuePair<Point, Actor>> для вашего объекта BlockSheet. Кстати, реализовав универсальный IEnumerable<T>, вы можете легко реализовать неуниверсальный IEnumerable через универсальный.

  • просто используйте бросок foreach (var (key,val) in blocksheet.Cast<KeyValuePair<Point, Actor>>()){/*loop body*/}. Но это не выглядит лучшим выбором, как по мне.

  • вы также можете реализовать Deconstruct для Object, но вы должны выяснить, как это должно вести себя для объектов, отличных от желаемых KeyValuePair, поэтому я настоятельно не рекомендую этот путь

      public static class Ext
      {
          public static void Deconstruct(this Object obj, out Point a, out Actor b)
          {
              if(obj is KeyValuePair<Point, Actor> pair)
              {
                  (a,b)=pair;
              }
              else
              {
                  a=null;
                  b=null;
                  // what can we do here?
              }
          }
      }
    

Спасибо @Serg - я сделал это, используя первое из ваших предложений. Мне впервые пришлось преобразовывать классы, реализующие необобщенные версии IEnumerable/IEnumerator. Я нашел эту статью Microsoft хорошим простым примером: связь

Richard Drysdall 17.05.2022 01:20

Другие вопросы по теме