web-dev-qa-db-ja.com

C#を使用したパラメータとしてのPassメソッド

私はすべて同じシグネチャ(パラメータと戻り値)を持つメソッドをいくつか持っていますが、名前とメソッドの内部が異なります。渡されたメソッドを呼び出す別のメソッドに実行するメソッドの名前を渡したい。

public int Method1(string)
{
    ... do something
    return myInt;
}

public int Method2(string)
{
    ... do something different
    return myInt;
}

public bool RunTheMethod([Method Name passed in here] myMethodName)
{
    ... do stuff
    int i = myMethodName("My String");
    ... do more stuff
    return true;
}

public bool Test()
{
    return RunTheMethod(Method1);
}

このコードは機能しませんが、これが私がやろうとしていることです。パラメータを定義する必要があるため、RunTheMethodコードの書き方がわかりません。

602
user31673

RunTheMethodメソッドのパラメータとして、.NET 3.5のFuncデリゲートを使用できます。 Funcデリゲートを使用すると、特定の型の多数のパラメータを受け取り、特定の型の単一の引数を返すメソッドを指定できます。これはうまくいくはずの例です:

public class Class1
{
    public int Method1(string input)
    {
        //... do something
        return 0;
    }

    public int Method2(string input)
    {
        //... do something different
        return 1;
    }

    public bool RunTheMethod(Func<string, int> myMethodName)
    {
        //... do stuff
        int i = myMethodName("My String");
        //... do more stuff
        return true;
    }

    public bool Test()
    {
        return RunTheMethod(Method1);
    }
}
743
Egil Hansen

あなたはデリゲートを使う必要があります。この場合、すべてのメソッドはstringパラメータを取り、intを返します。これは最も単純にFunc<string, int>デリゲートによって表されます。1。それであなたのコードはこれと同じくらい簡単な変更で正しくなることができます:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}

確かに、参加者はこれよりはるかに強力な権限を持っています。たとえば、C#ではlambda式からデリゲートを作成できるので、この方法でメソッドを呼び出すことができます。

RunTheMethod(x => x.Length);

それはこのような無名関数を作成します。

// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
    return x.Length;
}

そしてそのデリゲートをRunTheMethodメソッドに渡します。

イベントサブスクリプション、非同期実行、コールバックなど、あらゆる種類のデリゲートを使用できます。特にLINQを使用したい場合は、それらを読んでおく価値があります。私は article を持っていますが、これはデリゲートとイベントの違いについてのほとんどですが、とにかく役に立つかもしれません。


1 これはフレームワーク内の一般的な Func<T, TResult> デリゲート型に基づいています。あなたは簡単にあなた自身を宣言することができます:

public delegate int MyDelegateType(string value)

そして、代わりにパラメータをMyDelegateType型にします。

334
Jon Skeet

OPの例から:

 public static int Method1(string mystring)
 {
      return 1;
 }

 public static int Method2(string mystring)
 {
     return 2;
 }

あなたはAction Delegateを試すことができます!そして、あなたのメソッドを使って呼び出します。

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();   // note: the return value got discarded
      return true;
 }

RunTheMethod(() => Method1("MyString1"));

または

public static object InvokeMethod(Delegate method, params object[] args)
{
     return method.DynamicInvoke(args);
}

それからメソッドを呼び出すだけです

Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
98
Zain Ali
public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

使用法:

var ReturnValue = Runner(() => GetUser(99));
28
kravits88

引数としてstringを取り、intを返す関数を表すFunc<string, int>デリゲートを使用する必要があります。

public bool RunTheMethod(Func<string, int> myMethod) {
    // do stuff
    myMethod.Invoke("My String");
    // do stuff
    return true;
}

それを使ってください。

public bool Test() {
    return RunTheMethod(Method1);
}
11
Bruno Reis

実行時にどのメソッドが呼び出されるかを変更したい場合は、デリゲートを使用することをお勧めします。 http://www.codeproject.com/KB/cs/delegates_step1.aspx

それはあなたが呼び出すためのメソッドを格納するためのオブジェクトを作成することを可能にし、それが必要なときにあなたは他のメソッドにそれを渡すことができます。

6
MadcapLaugher

できるだけ完全な解決策を共有するために、私は3つの異なるやり方を提示することになるでしょう、しかし今、私は最も基本的な原則から始めるつもりです。


簡単な紹介

すべてのCLR( 共通言語ランタイム )言語(C#やVisual Basicなど)は、コードを実行するCLI( 共通言語インタプリタ )と呼ばれるVMの下で動作します。 CやC++(直接機械語にコンパイルされる)のような母国語よりも高いレベル。つまり、メソッドはいかなる種類のコンパイル済みブロックでもありませんが、CLRが認識して本体を引き出し、それをマシンコードのインライン命令に巻き戻すために使用する単なる構造化要素です。したがって、メソッドはそれ自体では値を生成しないため、メソッドをパラメータとして渡すことはできません。有効な式ではありません。だから、あなたはデリゲートの概念をつまずくつもりです。


代理人とは何ですか?

デリゲートはメソッドへのポインタを表します。 (上で述べたように)メソッドは値ではないため、CLR言語には特別なクラスDelegateがあります。そのクラスはあらゆるメソッドをラップしており、暗黙的にあらゆるメソッドをそれにキャストできます。

次の使用例を見てください。

static void MyMethod()
{
    Console.WriteLine("I was called by the Delegate special class!");
}

static void CallAnyMethod(Delegate yourMethod)
{
    yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}

static void Main()
{
    CallAnyMethod(MyMethod);
}

3つの方法

  • 方法1
    上記の例のようにDelegate特殊クラスを直接使用してください。この解決策の問題は、引数をメソッド宣言の引数の型に制限することなく、引数を動的に渡すときにコードがチェックされないことです。

  • 方法2/3 Delegate特殊クラスの他に、デリゲートの概念はカスタムデリゲートに広がっています。カスタムデリゲートは、delegateキーワードが先行するメソッドの宣言であり、通常のメソッドのように振る舞います。それらはとてもチェックされ、そしてあなたは " perfect "コードを思い付くでしょう。

次の例を見てください。

delegate void PrintDelegate(string Prompt);

static void PrintSomewhere(PrintDelegate print, string Prompt)
{
    print(Prompt);
}

static void PrintOnConsole(string Prompt)
{
    Console.WriteLine(Prompt);
}

static void PrintOnScreen(string Prompt)
{
    MessageBox.Show(Prompt);
}

static void Main()
{
    PrintSomewhere(PrintOnConsole, "Press a key to get a message");
    Console.Read();
    PrintSomewhere(PrintOnScreen, "Hello world");
}

独自のカスタムデリゲートを記述しないというこの方法による2番目のオプションは、システムライブラリ内で宣言されているもののいずれかを使用することです。

  • Actionは、引数なしでvoidをラップします。
  • Action<T1>は、1つの引数でvoidをラップします。
  • Action<T1, T2>は2つの引数でvoidをラップします。
  • 等々...
  • Func<TR>TR戻り型で、引数なしで関数をラップします。
  • Func<T1, TR>は、戻り値の型がTR、引数が1つの関数をラップします。
  • Func<T1, T2, TR>TR戻り型と2つの引数で関数をラップします。
  • 等々...

(この後者の解決策は、多くの人が投稿したことです。)

6
Davide Cannizzo

受け入れられた答えは絶対に正しいですが、私は追加の方法を提供したいと思います。

私は自分自身で同じような質問に対する解決策を探した後にここに行きました。私はプラグイン駆動のフレームワークを構築しています。その一部として、実際のMenuオブジェクトを公開せずにアプリケーションメニューのメニュー項目を汎用リストに追加できるようにしたいと考えました。 Menu UIオブジェクトメニューに関する一般的な情報を追加するのは十分に簡単ですが、プラグイン開発者がメニューがクリックされたときにコールバックを作成するのに十分な自由を与えるのは面倒なことです。ホイールと通常のメニューの呼び出しを再発明し、イベントからのコールバックをトリガーしようとしていたことが私に明らかになるまでは!

それで、あなたがそれを理解したらそれが聞こえるように単純な解決策は今まで私を避けました。

必要に応じてベースから継承した現在の各メソッドに対して別々のクラスを作成し、それぞれにイベントハンドラを追加するだけです。

2
Wobbles

これは、関数をパラメータとして渡す方法を理解しやすくするための例です。

Parent というページがあり、子ポップアップウィンドウを開きたいとします。親ページには、子ポップアップテキストボックスに基づいて入力する必要があるテキストボックスがあります。

ここであなたはデリゲートを作成する必要があります。

Parent.cs //デリゲートの宣言パブリックデリゲートvoid FillName(String FirstName);

今すぐあなたのテキストボックスを埋める関数を作成し、関数はデリゲートをマップする必要があります

//parameters
public void Getname(String ThisName)
{
     txtname.Text=ThisName;
}

ボタンをクリックすると、Childポップアップウィンドウを開く必要があります。

  private void button1_Click(object sender, RoutedEventArgs e)
  {
        ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor

         p.Show();

    }

IN ChildPopUpコンストラクタあなたは親//ページの 'delegate type'のパラメータを作成する必要があります

ChildPopUp.cs

    public  Parent.FillName obj;
    public PopUp(Parent.FillName objTMP)//parameter as deligate type
    {
        obj = objTMP;
        InitializeComponent();
    }



   private void OKButton_Click(object sender, RoutedEventArgs e)
    {


        obj(txtFirstName.Text); 
        // Getname() function will call automatically here
        this.DialogResult = true;
    }

これはパラメータなしの例です: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

paramsで: http://www.daniweb.com/forums/thread98148.html#

あなたは基本的にメソッドの名前と一緒にオブジェクトの配列を渡します。その後、両方をInvokeメソッドで使用します。

params Object []パラメータ

0
Jeremy Samuel