2016-09-25 7 views
0

Я пытаюсь написать функцию, которая принимает другую функцию в качестве параметра (и его вызовы позже). Я знаю, что ее выполнимость, если я знаю signature of the function beforehand, но возможно ли это, если я не? (Например, передавая функцию в качестве параметра в JavaScript)Передача общего метода в качестве параметра в C#

Например:

// this should accept a function with any kind of signature and return value 
void DelayedCall(?? functionToCallLater, float delayInSecs, params object[] values) 
{ 
    //here do something like (just as an example) 
    functionToCallLater.Invoke(values); 
} 

EDIT: Я не хочу предполагать ничего о functionToCallLater Он может выглядеть как это, например:

int MyFunc() 
    void MyFunc2() 
    void MyFunc3(int someParam) 
    string MyFunc4(int someParam, MyClass someOtherParam) 
    void MyFunc5<T>(params T[] values) 
+1

Вместо этого вы должны принять лямбда. – SLaks

ответ

1

Вы имеете в виду это? :

void DelayedCall<T>(Action<T> functionToCallLater, 
    float delayInSecs, params T[] values) 
{ 
    //here do something like (just as an example) 
    functionToCallLater(values); 
} 

У вас есть объект [], как ваши ценности, но я предполагаю, что вы хотите, чтобы определить их тип, а также с использованием общего. Кроме того, поскольку он не выглядит так, как ваш метод, который вы вызываете, не имеет типа возврата, я использовал Action<T> вместо Func<T>.

Основываясь на комментарий ниже,

Если вы хотите принимать различные подписи, у вас действительно есть 2 различных вариантов. Первый, как сказал Слакс, - использовать отражение. Это может стать чрезвычайно сложным, поскольку вам нужно будет определить положение и типы параметров в функцииToCallLater и выровнять их с входящими параметрами из родительской функции. Есть много семантики, которые действительно делают это трудным (хотя это возможно) и действительно больше проблем, чем хуже, когда проблема обобщается для обработки большого числа случаев.

Второй и более проверяемый способом обработки этого сценария (хотя и не обязательно меньше работы), является созданием перегрузок для рассматриваемого метода:

void DelayedCall<T>(Func<T> functionToCallLater, 
     float delayInSecs, params T[] values) 

void DelayedCall<T,R>(Func<T,R> functionToCallLater, 
     float delayInSecs, params T[] values) 

void DelayedCall<T>(Func<T,X,R> functionToCallLater, 
     float delayInSecs, params T[] values) 

etc. 

В зависимости от того, насколько сложного метода перегрузки является, это может быть немного утомительным почти невозможным, но он будет работать. Реальный вопрос, который вы хотите задать себе в этом сценарии, заключается в следующем: «Это оптимальный способ справиться с этим подходом?» Например, если вы не нуждаетесь в возвращаемом значении в вызывающем методе, зачем вообще его разрешать? Вы всегда можете заставить абонент обернуть функцию в другом методе, который прилипает к подписи методы следующим образом:

void DelayedCall<T>(Action<T> functionToCallLater, 
     float delayInSecs, params T[] values) 
.... 
DelayledCallAction<int>(
    (i) => MyMethodWhichReturnsSomething(i), 
    floadDelayInSecs, 1,2,3); 

Это устраняет некоторые из сценариев и функциональности метод должен обрабатывать. Путем сокращения возможных параметров, которые должна обрабатывать подпись метода, проблема становится более простой и управляемой.

+0

Что делать, если я не хочу предполагать что-либо о методе (= он может иметь 0 параметров и без возвращаемого значения)? Например, я хочу, чтобы эта функция принимала любое из них в качестве параметра: 'int MyFunc() {return 6; } void MyFunc2() {} void MyFunc3 (int someParam) {} string MyFunc4 (строка param1, MyClass param2) {} ' – sydd

+0

Я добавил дополнительную информацию на основе вашего комментария – kemiller2002

+0

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

2

Если вы ничего не знаете о функции, вам нужно будет использовать Reflection (и заплатить штраф за производительность).

Задать ему вопрос Delegate, затем звонить по номеру .DynamicInvoke().

+0

это не работает, если функция имеет необязательные параметры. – sydd

+0

@sydd: Необязательные параметры - это чисто синтаксическая функция; они все еще требуются через Reflection. – SLaks

0

Я думаю, что это будет probihitely многословным в C#:/

Heres решение, которое может принять функцию, которая возвращает или не возвращает значение и принимает 0 - 2 параметра:

// signature: void MyFunc() 
    void DelayedCall(Action sdf, float delayInSecs) 
    { 
    } 

    // signature: SomeClass MyFunc() 
    void DelayedCall<T>(Func<T> sdf, float delayInSecs) 
    { 
    } 

    // signature: void MyFunc(SomeClass param1) 
    void DelayedCall<T>(Action<T> sdf, float delayInSecs, T values) 
    { 
    } 

    // signature: SomeClass MyFunc(SomeClass param1) 
    void DelayedCall<T, K>(Func<T, K> sdf, float delayInSecs, T values) 
    { 
    } 

    // signature: void MyFunc(SomeClass param1, SomeClass2 param2) 
    void DelayedCall<T, K>(Action<T, K> sdf, float delayInSecs, T values, K values2) 
    { 
    } 

    // signature: SomeClass MyFunc(SomeClass param1, SomeClass2 param2) 
    void DelayedCall<T, K, L>(Func<T, K, L> sdf, float delayInSecs, T values, K values2) 
    { 
    } 

Эти например, следующее:

void MyFunc1() { } 
    int MyFunc2() { return 6; } 
    void MyFunc3(int someParam) { } 
    string MyFunc4(string someParam) { return ""; } 
    void MyFunc5(int someParam, string someparam2) { } 
    string MyFunc6(string someParam, int someparam2) { return ""; } 
Смежные вопросы