Как передать функцию в качестве параметра в C#?

Можно ли передать функцию в качестве параметра в C#? Я могу сделать это с помощью классов Func или Action, но это заставляет меня сразу объявить всю сигнатуру функции. Когда я пытаюсь использовать Delegate, я получаю сообщение об ошибке компиляции, в котором говорится, что он не может преобразовать группу методов в Delegate.

Я работаю над Осевой и пытаюсь разрешить пользователям вызывать веб-службы. Я собираюсь создать прокси-класс Visual Studio, а затем передать сгенерированную функцию. Подпись функции не имеет значения, потому что сгенерированный код использует только имя функции. Однако я хотел бы передать функцию вместо имени по двум причинам: возможность использовать свойство Url прокси и ошибка компилятора, если веб-служба не существует или обновляется в Visual Studio.


public void AlertIt(object o) {
    Axial.DOM.Window.Alert(o.ToString());
}
public void CallAddService() {
    object[] param = new object[] { int.Parse(txtA.Text), int.Parse(txtB.Text) };
    Axial.ServerScript.CallWebService(new WSProxy.WS().Add, param, AlertIt, AlertIt);
}

class Axial.ServerScript {
    public void CallWebService(Delegate method, object[] param, Action<object> successCallback, Action<object> failureCallback) {
        // translate to javascript (already working)
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
55
0
97 748
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

Пример делегата

почему вы используете отражение? будет ли когда-нибудь другое количество параметров? или знаете ли вы, что сигнатура метода останется неизменной (также помните, что C# поддерживает ключевое слово params [])

параметры C#

HTH

Кости

Сначала у вас должен быть делегат

delegate int Operation(int a, int b)

тогда это становится:

public void InvokeMethod(Operation method, object target, object param)
{
    method((int) target, (int) param);
}

Нет необходимости звонить в Invoke.

Как и в случае с dbone, я не уверен, зачем вам нужен массив params []. Не могли бы вы пояснить расширенное использование параметров?

Кроме того, мне придется кое-что исправить в вашем вопросе, потому что это вызовет ошибку компиляции: p

Что-то вроде этого должно сработать для вас:

delegate int MyDelegate(int a, int b);
public int Add(int a, int b) {
    return a + b;
}
public void InvokeMethod(Delegate method, object[] param) {
    Console.WriteLine(method.DynamicInvoke(param));
}
public Form1() {       
    InitializeComponent();
    InvokeMethod(new MyDelegate(Add), new object[] { 1, 2 });
}

Удачи!

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

Я думаю, что вам нужно:

static object InvokeMethod(Delegate method, params object[] args){
    return method.DynamicInvoke(args);
}

static int Add(int a, int b){
    return a + b;
}

static void Test(){
    Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}

Печать «9».

Есть ли способ не требовать часть кода "new Func <int, int, int>"? Схема использования очень важна.

Dan Goldstein 19.12.2008 15:53

Единственный способ, который приходит в голову, - это заставить InvokeMethod принимать Func <int, int, int> вместо Delegate. Но тогда вам понадобится другая перегрузка InvokeMethod для каждой комбинации параметров типа для Func <>, которую вы когда-либо увидите.

P Daddy 19.12.2008 17:01

Отметим, что использование DynamicInvoke связано со значительными затратами - по возможности используйте делегат напечатанный и Invoke (намного быстрее).

Marc Gravell 25.06.2010 09:27

Спасибо за это. Это действительно помогло мне объяснить это другому разработчику. здесь.

Ryan Ternier 09.11.2011 22:24

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

public void InvokeMethod(Action action)
{
    action();
}

public int Add(int a, int b)
{
    return a + b;
}

public void Test()
{    
    InvokeMethod(() => Add(2, 3));
}

Это в основном задерживает вызов обычным способом, но путем обертывания фактического вызова Add в простой делегат Action.

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

Обновлено: если это сгенерированный код, вы можете выполнить приведение к Func<...> с правильными аргументами типа - при условии, что их не слишком много. Кроме этого, нет реального способа просто передать группу методов. Были случайные вызовы оператора «infoof (...)» (например, typeof, но для членов), который дал бы вам MemberInfo, но его на самом деле не существует.

Это очень близко, но затрудняет использование API. Я обновил вопрос, чтобы точно сказать, что я делаю.

Dan Goldstein 19.12.2008 16:08

Кстати, этот код требует компиляции с помощью инструментов C# 3.0. (Просто установите проект в .Net framework 3.5)

Jon Adams 10.11.2009 18:28

Но здесь Test () и InvokeMethod () возвращают void, поэтому результат Add () не может быть возвращен.

Abhishikt N. Jain 16.01.2014 06:13

@ AbhishiktN.Jain: Ничего такого пытающийся, чтобы вернуть значение Add. Мы просто вызываем InvokeMethod с делегатом, который является результатом преобразования лямбда-выражения. Вы пробовали этот код?

Jon Skeet 16.01.2014 10:46

Посмотрите на Серия функционального программирования Джастина Этереджа. Там вы должны найти решение своей проблемы.

Эта серия не обязательно связана, но я читаю ее, потому что она интересная. Это дало мне идею шаблонной функции, которая работала бы, если бы вывод типа C# был лучше.

Dan Goldstein 22.12.2008 16:48

Скажем, если вам нужно передать метод как параметр, а также вам нужно поймать возвращаемое значение для дальнейшей обработки. Тогда приведенные выше примеры будут работать нормально. Но скажем, если вам нужно передать метод с возвращаемым типом void, тогда вам нужно создать еще одну версию функции InvokeMethod. Посмотрите на пример ниже.

private static T retry<T>(Delegate method, params object[] args)
{
    for (int i = 0; i <= 3; i++)
    {
        try
        {
            return (T)method.DynamicInvoke(args);
        }
        catch (Exception ex)
        {
            if (i == 3)
            {
                logMessage(ex.Message);
            }
            Console.WriteLine("Retry count " + i);
            Thread.Sleep(10);
        }
    }
    return default(T);
}

private static void retry2(Delegate method, params object[] args)
{
    for (int i = 0; i <= 3; i++)
    {
        try
        {
            method.DynamicInvoke(args);
            break;
        }
        catch (Exception ex)
        {
            if (i == 3)
            {
                logMessage(ex.Message);
                //return default(T);
            }
            Console.WriteLine("Retry count " + i);
            Thread.Sleep(10);
        }
    }
}
static bool isSuccess = true;
static void logMessage(string msg)
{
    isSuccess = false;
    Console.WriteLine(msg);
}

static int Add(int a, int b)
{
    return a + b;
}

static void Add2(int a, int b)
{
    int c = a + b;
    Console.WriteLine(c);
}

static void Main(string[] args)
{
    int d = retry<int>(new Func<int, int, int>(Add), 6, 7.7);
    Console.Write("  " + d + "\n"+isSuccess);

    retry2(new Action<int, int>(Add2), 45, 60);

    Console.ReadKey();
}

Это очень простой пример для программиста, который уже знаком с функцией передачи в стиле (C / C++ / VB.NET/Python) с помощью указатель / ссылкаC# делегат):

        delegate void CALLBACK(String s);
        static void Main(string[] args)
        {

            Get("some string", testfunc);

            Util.pause();
        }

        static void Get(String s, CALLBACK x)
        {
            x(s);
        }


        static void testfunc(String s)
        {
            Console.WriteLine(s);
        }

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