Можно ли передать функцию в качестве параметра в 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)
}
}





пожалуйста, взгляните на использование делегатов, вот отличный пример
почему вы используете отражение? будет ли когда-нибудь другое количество параметров? или знаете ли вы, что сигнатура метода останется неизменной (также помните, что C# поддерживает ключевое слово params [])
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».
Единственный способ, который приходит в голову, - это заставить InvokeMethod принимать Func <int, int, int> вместо Delegate. Но тогда вам понадобится другая перегрузка InvokeMethod для каждой комбинации параметров типа для Func <>, которую вы когда-либо увидите.
Отметим, что использование DynamicInvoke связано со значительными затратами - по возможности используйте делегат напечатанный и Invoke (намного быстрее).
Спасибо за это. Это действительно помогло мне объяснить это другому разработчику. здесь.
Преобразование группы методов, анонимного метода или лямбда-выражения в делегат требует, чтобы компилятор знал точный тип делегата. Однако вы потенциально можете использовать лямбда-выражения и захваченные переменные, чтобы упростить это:
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. Я обновил вопрос, чтобы точно сказать, что я делаю.
Кстати, этот код требует компиляции с помощью инструментов C# 3.0. (Просто установите проект в .Net framework 3.5)
Но здесь Test () и InvokeMethod () возвращают void, поэтому результат Add () не может быть возвращен.
@ AbhishiktN.Jain: Ничего такого пытающийся, чтобы вернуть значение Add. Мы просто вызываем InvokeMethod с делегатом, который является результатом преобразования лямбда-выражения. Вы пробовали этот код?
Посмотрите на Серия функционального программирования Джастина Этереджа. Там вы должны найти решение своей проблемы.
Эта серия не обязательно связана, но я читаю ее, потому что она интересная. Это дало мне идею шаблонной функции, которая работала бы, если бы вывод типа C# был лучше.
Скажем, если вам нужно передать метод как параметр, а также вам нужно поймать возвращаемое значение для дальнейшей обработки. Тогда приведенные выше примеры будут работать нормально. Но скажем, если вам нужно передать метод с возвращаемым типом 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);
}
Есть ли способ не требовать часть кода "new Func <int, int, int>"? Схема использования очень важна.