簡體   English   中英

在C#中將通用方法作為參數傳遞

[英]Passing a generic method as a parameter in C#

我正在嘗試編寫一個函數,該函數將另一個函數作為參數(並在以后調用),如果我事先知道該函數簽名,我知道它是可行的,但是如果我不知道,這是可能的嗎? (例如,將函數作為參數傳遞給JavaScript)

例如:

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

編輯:我不想承擔有關functionToCallLater任何事情,例如,它們可能看起來像這樣:

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

如果您對該功能一無所知,則需要使用Reflection(並支付性能損失)。

使它接受Delegate ,然后調用.DynamicInvoke()

你是這個意思嗎

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

您有object []作為值,但是我假設您也想使用泛型來指定它們的類型。 另外,由於看起來好像您要調用的方法沒有返回類型,所以我使用Action<T>代替Func<T>

根據以下評論,

如果要接受不同的簽名,則實際上有2個不同的選項。 像SLaks所說的第一個是使用反射。 但是,這可能變得非常復雜,因為您將不得不確定functionToCallLater中參數的位置和類型,並將其與父函數的傳入參數對齊。 有很多語義確實使這一點變得困難(盡管有可能),並且使問題普遍化以處理大量案例時,確實帶來了更多的麻煩。

處理此場景的第二種且更可驗證的方法(盡管不一定要減少工作量)是為有問題的方法創建重載:

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

這消除了該方法需要處理的一些方案和功能。 通過減少方法簽名需要處理的可能選項,問題將變得更簡單,更易於管理。

我認為這在C#中可能是冗長的:/

這是一個可以接受返回或不返回值並接受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 "";  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM