Не удается преобразовать группу методов в действие

Я застрял с этой ошибкой, но не знаю, как ее исправить.

Я пытаюсь передать метод в качестве параметра другой функции в качестве действия. У меня есть интерфейс, который определяет два метода:

//ISegment interface
void SetNodeA(in INode node);
void SetNodeB(in INode node);

Затем я создаю сегмент и хочу передать этот метод в другую функцию:

ISegment segment = GetSegment();
Execute(start, segment.SetNodeA);
Execute(end, segment.SetNodeB);

Моя функция выполнения выглядит так:

void Execute(in EndPoint point, in Action<INode> fnc)
{
    Verify(segment);
    Verify(point.Node);
    fnc?.Invoke(point.Node); //set the node
}

Проблема в том, что я получаю эту ошибку:

Argument 2: cannot convert from 'method group' to 'in Action'

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

Есть ли у вас веская причина использовать in в ваших ISegment методах? Я спрашиваю, потому что, если вы удалите их, ваш код будет работать нормально.

Kirk Woll 23.04.2022 00:43

О, вот причина. Я часто использую in как привычку, чтобы строго следить за тем, чтобы это нельзя было изменить. Это просто делает меня менее склонным к ошибкам. Как это не позволяет in ?

WDUK 23.04.2022 00:46

@WDUK in с интерфейсами по такой причине бессмысленно, потому что интерфейс без дженериков всегда будет рассматриваться как ссылочный тип, и вы не можете изменить входящую ссылку (поэтому она наблюдается вызывающей стороной), если вы не используете специальный модификатор.

Guru Stron 23.04.2022 00:51

Ах, я понимаю эту причину, но, к сожалению, это не основная цель ключевого слова in здесь. Он предназначен для того, чтобы вы могли передавать значения по ссылке (например, ref и out), но не позволяли изменять параметр. Из MSFT: «Добавьте модификатор in для передачи аргумента по ссылке и объявите о намерении вашего проекта передавать аргументы по ссылке, чтобы избежать ненужного копирования. Вы не собираетесь изменять объект, используемый в качестве этого аргумента». Но почему это нарушает вывод типа дженериков — хороший вопрос.

Kirk Woll 23.04.2022 00:52

О, так что использование in для ссылочных типов в значительной степени бессмысленно. Хорошо, теперь я понимаю! Спасибо :)

WDUK 23.04.2022 00:56

@KirkWoll, почему ты в это веришь?

Guru Stron 23.04.2022 00:57

@WDUK да, вы все равно сможете изменить сам экземпляр, и параметр in не препятствует этому.

Guru Stron 23.04.2022 00:58

@KirkWoll «Но почему это нарушает вывод типа дженериков — хороший вопрос». Насколько я знаю, это не так, проблема в том, что Action и Func не поддерживают передачу параметра по ссылке.

Guru Stron 23.04.2022 00:59

@KirkWoll то, что я написал, касается модификатора параметра in.

Guru Stron 23.04.2022 01:00

@GuruStron, ах, мои извинения. Когда вы сказали: «Потому что интерфейс без дженериков всегда будет рассматриваться как ссылочный тип», я подумал, что вы имеете в виду интерфейс ISegment, а не интерфейс INode. Но теперь я понимаю. Я удалю свои ошибочные комментарии.

Kirk Woll 23.04.2022 01:02

@KirkWoll Нет проблем. Моя формулировка/объяснение была далека от совершенства. Я имел в виду случай, когда Get<T>(in T t) where T : ISegment - в этом случае, если T является типом значения, реализующим ISegment, то in может иметь смысл.

Guru Stron 23.04.2022 01:04
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы 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.
3
11
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно либо удалить модификатор параметра in из подписи SetNodeX, либо использовать собственный делегат для второго параметра Execute:

public interface ISegment
{
    void SetNodeA(in INode node);
    void SetNodeB(INode node); // in removed
}

public delegate void DelegateWithIn(in INode node);

void Execute(in EndPoint point, DelegateWithIn fnc)
{
}
void Execute1(in EndPoint point, Action<INode> fnc)
{
}

Execute(null, segment.SetNodeA); // uses custom delegate
Execute1(null, segment.SetNodeB); // uses Action

Как я упоминал в комментариях, делегаты Action и Func не поддерживают модификаторы параметров in, out и ref.

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

Проблема в том, что ваши методы SetNodeA и SetNodeB имеют параметр inи, который вы пытаетесь вызвать через Action<T>, который поддерживает параметры in, out или ref в нет.

Если вам нужно продолжать использовать in для этих методов, вы можете добиться этого, создав собственный тип делегата и используя его вместо Action<T>:

public delegate void ActionWithInParam<T>(in T node);

Тогда ваш метод Execute будет выглядеть примерно так:

void Execute(in EndPoint point, ActionWithInParam<INode> fnc)
{
    Verify(segment);
    Verify(point.Node);
    fnc?.Invoke(point.Node); //set the node
}

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