WedX - журнал о программировании и компьютерных науках

Индексатор с именем Item требуется интерфейсом, но его невозможно реализовать?

Я пытаюсь реализовать интерфейс класса в API ESPRIT, для которого требуется индексатор с именем «Элемент». (Я предполагаю, что интерфейс пришел из VB.NET, но у меня нет источника.) Очевидно, что индексатор «Item[index]» автоматически генерируется компилятором по умолчанию, но я получаю следующие ошибки:

Ошибки

Я понимаю, что [System.Runtime.CompilerServices.IndexerName("Item")] избыточен; это просто для того, чтобы явно продемонстрировать, что Item генерируется, а ошибка остается.

Попытка реализовать public ToolBarControl Item[int index] разрушает весь остальной класс.

Edit1: На третьем снимке экрана показано IToolBar.this, но я попробовал IToolBar.Item с результатом, указанным выше.

Похоже, я не первый, кто запросил именованные итераторы, но я думаю, что сгенерированный именованный индексатор должен удовлетворять этому требованию. https://github.com/dotnet/csharplang/issues/471

Как мне реализовать этот индексатор, чтобы удовлетворить интерфейс?


Примечание. Я вношу следующее редактирование для полноты картины, устранения неполадок в будущем и ответов на вопросы, заданные в комментариях, но я уже знаю, что решение для этого конкретного случая реализует get_Item(int index), как указано в принятом ответе.

Edit2: Чтобы ответить на вопрос "что предлагает визуальная студия?" Как видите, перед заменой он знает, что Index будет ошибкой, потому что для Item не определен параметр Index (я проверял это, и он действительно не работает). Ни один из двух других вариантов автоматической реализации не работает. Предложение Visual Studio

Edit3: из браузера объектов внутри IToolBar, Item[int] определяется как: Определение элемента


  • Есть ли документация по API для этой пользовательской библиотеки, которую вы используете? 23.08.2018
  • После удаления собственного кода, что предлагает Visual Studio в качестве реализации, когда вы наводите курсор на Esprit.Tooolbar? 23.08.2018
  • Какова спецификация интерфейса для этого отсутствующего члена? 23.08.2018
  • Вы уверены, что возвращаемый тип this[] — «ToolBarControl»? 23.08.2018
  • Если вы не можете найти документацию, откройте ссылку в дизассемблере и посмотрите, что конкретно он ищет. @Neil может быть прав, он может ожидать «объект» от индексатора или «IToolbarControl». 23.08.2018
  • @ParrishHusband Документация есть, но в ней не рассматривается подкласс Esprit.Toolbar. См. дополнительную информацию, добавленную в вопрос, для ответа на предложенную реализацию VS. 24.08.2018
  • @Neil Я проверил тип возвращаемого значения. См. дополнительное редактирование и снимок экрана для определения Item[int] в IToolBar из обозревателя объектов. 24.08.2018

Ответы:


1

C# может удовлетворить этот «индексатор» .Item из интерфейса с get_Item. Это связано с тем, как во время компиляции IL генерируются геттеры и установщики свойств/индексов.

Вот как это описано в спецификации CLI:

I.10.4 Шаблоны именования

Для свойств:

Отдельное свойство создается путем выбора типа, возвращаемого его методом получения, и типов параметров получателя (если они есть). Затем создаются два метода с именами, основанными на имени свойства и этих типах. В приведенных ниже примерах мы определяем два свойства: Имя не принимает параметров и возвращает значение System. .String, а Item принимает параметр System.Object и возвращает System.Object. Элемент называется индексированным свойством, что означает, что он принимает параметры и, таким образом, может отображаться для пользователя как массив с индексами.

PropertyGet, used to read the value of the property
   Pattern: <PropType> get_<PropName> (<Indices>)
   Example: System.String get_Name ();
   Example: System.Object get_Item (System.Object key);
PropertySet, used to modify the value of the property
   Pattern: void set_<PropName> (<Indices>, <PropType>)
   Example: void set_Name (System.String name);
   Example: void set_Item (System.Object key, System.Object value); 

Поэтому вы должны быть в состоянии выполнить условия реализации индексатора примерно так:

public class ManagedEspritToolbar : Esprit.Toolbar
{
    public ToolbarControl get_Item(int index) => Toolbar[index];
}

Для проверки этого вы можете создать простой интерфейс в VB.NET:

Public Interface IVBNetInterface
    Property Item(index As Integer) As String
End Interface

Затем реализуйте интерфейс в новом классе на C#. Обратите внимание, что по умолчанию используется get_Item/set_Item средств доступа, когда среда IDE может автоматически реализовывать интерфейс:

public class CSharpClass : IVBNetInterface
{
    public string get_Item(int index)
    {
        throw new NotImplementedException();
    }

    public void set_Item(int index, string Value)
    {
        throw new NotImplementedException();
    }
}

Чтение сгенерированного IL интерфейса подтверждает это поведение:

введите здесь описание изображения


Как насчет свойства по умолчанию VB.NET?

В VB.NET есть декоратор свойств Default, который, по сути, является механизмом объявления индексатора в классе:

Public Interface IVBNetInterface
    Default Property Item(index As Integer) As String
End Interface

Когда это правильно реализовано в классе/интерфейсе VB.NET, стандартная реализация индексации C# this[int] будет работать. Поэтому обходной путь get_Item должен быть действительно необходим только тогда, когда атрибут по умолчанию не правильно применен к свойству целевого индекса. Обратите внимание на добавление атрибута System.Reflection.DefaultMemberAttribute при исследовании кода IL после его применения:

введите здесь описание изображения


Улучшение использования:

Чтобы обойти базовые классы/интерфейсы, не написанные с модификатором Default, вы можете явно реализовать интерфейсные индексаторы, что позволяет использовать традиционный индексатор в стиле C# для класса:

public class CSharpClass : IVBNetInterface
{
    public string this[int index]
    {
        get => throw new NotImplementedException();
        set => throw new NotImplementedException();
    }

    #region IVBNetInterface

    string IVBNetInterface.get_Item(int index) => this[index];

    void IVBNetInterface.set_Item(int index, string value) => this[index] = value;

    #endregion
}

Это может быть предпочтительным подходом, если вы хотите, чтобы использование класса выводилось с помощью типичного индексатора, при этом удовлетворяя базовому требованию Interface.Item.

23.08.2018
  • Я реализовал get_Item как public ToolBarControl get_Item(int index) => ToolBar.Item[index];, и это (как ни странно) удовлетворило требованию Item[int] get. Хотите добавить аннотацию TLDR в верхней части вашего ответа, в которой говорится, что get_Item(int index) может удовлетворить требование Item к интерфейсу? 24.08.2018
  • @Still.Tony, я работал с другой сторонней библиотекой, написанной на VB.NET, и заметил несколько похожее поведение. Если у вас есть дизассемблер IL, возможно, стоит взглянуть на IToolbar, чтобы увидеть базовый код. Возможно, где-нибудь обновите свой вопрос с помощью «Esprit», чтобы другие могли найти это. 24.08.2018

  • 2

    Проблема в том, что не существует допустимого синтаксиса C# для объявления именованного индексатора, поэтому вы не можете удовлетворить этот интерфейс с помощью C#. Было несколько запросов на реализацию именованных индексаторов в C#, и все они были проигнорированы или полностью отклонены языковой группой C#. Похоже, они не хотят реализовывать эту функцию в C#. Может быть, если они передумают позже, ты сможешь сделать укол.

    Единственный способ, которым я могу подойти к этому в настоящее время, - это создать библиотеку VB.NET с классом, который реализует интерфейс и действует либо как оболочка, либо как базовый класс для вашего собственного класса.

    22.08.2018
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]