web-dev-qa-db-ja.com

C#でパラメータとして関数を渡す方法は?

C#で関数をパラメーターとして渡すことはできますか? FuncクラスまたはActionクラスを使用して実行できますが、これにより関数シグネチャ全体を一度に宣言する必要があります。デリゲートを使用しようとすると、メソッドグループをデリゲートに変換できないというコンパイルエラーが表示されます。

私は Axial に取り組んでおり、ユーザーにWebサービスの呼び出しを許可しようとしています。私が目指しているのは、Visual Studioプロキシクラスを作成し、生成された関数を渡す機能です。生成されたコードは関数名のみを使用するため、関数の署名は重要ではありません。ただし、次の2つの理由で、名前の代わりに関数を渡します。プロキシのUrlプロパティを使用する機能と、Webサービスが存在しないか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)
    }
}
55
Dan Goldstein

私はあなたが欲しいと思う:

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」を印刷します。

52
P Daddy

メソッドグループ、匿名メソッド、またはラムダ式をデリゲートに変換するには、コンパイラが正確なデリゲートタイプを認識する必要があります。ただし、ラムダ式とキャプチャされた変数を使用して、これを簡単にすることができます。

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<...>適切な型引数を使用-多すぎることはないと仮定します。それ以外には、メソッドグループを渡すだけの実際の方法はありません。 Memberinfoを提供する「infoof(...)」演算子(typeofに似ていますが、メンバー用)が時々呼び出されますが、実際には存在しません。

46
Jon Skeet

最初に代理人が必要です

delegate int Operation(int a, int b)

その後:

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

Invokeを呼び出す必要はありません。

Dboneと同様に、なぜparams []配列が必要なのかわかりません。 paramsの拡張された使用法を明確にしますか?

また、私はあなたの質問で何かを修正する必要があります、それはコンパイルエラーを引き起こすからです:p

4
Jon Limjap

これは、(C/C++/VB.NET/Python)pointer/ref(with 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
dns

デリゲートの使用方法をご覧ください

デリゲートの例

なぜリフレクションを使用しているのですか?異なる数のパラメーターがありますか?または、メソッドの署名が一定のままであることを知っていますか(C#がparams []キーワードをサポートしていることも覚えています)

params c#

HTH

骨格

3
dbones

Functional Programming Series Justin Etheredgeをご覧ください。そこで問題の解決策を見つける必要があります。

3
Jarek

メソッドをパラメーターとして渡す必要があるだけでなく、さらに処理するために戻り値をキャッチする必要がある場合もあります。その後、上記の例は問題なく動作します。しかし、戻り値の型がvoidのメソッドを渡す必要がある場合は、InvokeMethod関数のもう1つのバージョンを作成する必要があります。以下の例を確認してください。

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();
}
2
Arup C

このような何かがあなたのために働くはずです:

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

がんばろう!

1
Mark Carpenter