Как передать функцию в качестве параметра в C #? - PullRequest
55 голосов
/ 19 декабря 2008

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

Я работаю над Axial и пытаюсь разрешить пользователям вызывать веб-сервисы. Я собираюсь создать прокси-класс 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)
    }
}

Ответы [ 8 ]

52 голосов
/ 19 декабря 2008

Я думаю, что вы хотите:

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".

46 голосов
/ 19 декабря 2008

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

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, но на самом деле его не существует.

4 голосов
/ 19 декабря 2008

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

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

3 голосов
/ 26 июля 2013

Это очень простой пример для программиста, который уже знаком с функцией передачи ( C / C ++ / VB.NET/Python)-style указатель / ref 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);
        }
3 голосов
/ 19 декабря 2008

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

3 голосов
/ 19 декабря 2008

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

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

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

params c #

НТН

Кости

2 голосов
/ 23 июня 2011

Скажите, если вам нужно передать метод в качестве параметра, а также вам нужно перехватить возвращаемое значение для дальнейшей обработки. Тогда приведенные выше примеры будут работать нормально. Но, скажем, если вам нужно передать метод с возвращаемым типом 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();
}
1 голос
/ 19 декабря 2008

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

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 });
}

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...