私はすべて同じシグネチャ(パラメータと戻り値)を持つメソッドをいくつか持っていますが、名前とメソッドの内部が異なります。渡されたメソッドを呼び出す別のメソッドに実行するメソッドの名前を渡したい。
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コードの書き方がわかりません。
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);
}
}
あなたはデリゲートを使う必要があります。この場合、すべてのメソッドは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
型にします。
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"));
public static T Runner<T>(Func<T> funcToRun)
{
//Do stuff before running function as normal
return funcToRun();
}
使用法:
var ReturnValue = Runner(() => GetUser(99));
引数として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);
}
実行時にどのメソッドが呼び出されるかを変更したい場合は、デリゲートを使用することをお勧めします。 http://www.codeproject.com/KB/cs/delegates_step1.aspx
それはあなたが呼び出すためのメソッドを格納するためのオブジェクトを作成することを可能にし、それが必要なときにあなたは他のメソッドにそれを渡すことができます。
できるだけ完全な解決策を共有するために、私は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);
}
方法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つの引数で関数をラップします。(この後者の解決策は、多くの人が投稿したことです。)
受け入れられた答えは絶対に正しいですが、私は追加の方法を提供したいと思います。
私は自分自身で同じような質問に対する解決策を探した後にここに行きました。私はプラグイン駆動のフレームワークを構築しています。その一部として、実際のMenu
オブジェクトを公開せずにアプリケーションメニューのメニュー項目を汎用リストに追加できるようにしたいと考えました。 Menu
UIオブジェクトメニューに関する一般的な情報を追加するのは十分に簡単ですが、プラグイン開発者がメニューがクリックされたときにコールバックを作成するのに十分な自由を与えるのは面倒なことです。ホイールと通常のメニューの呼び出しを再発明し、イベントからのコールバックをトリガーしようとしていたことが私に明らかになるまでは!
それで、あなたがそれを理解したらそれが聞こえるように単純な解決策は今まで私を避けました。
必要に応じてベースから継承した現在の各メソッドに対して別々のクラスを作成し、それぞれにイベントハンドラを追加するだけです。
これは、関数をパラメータとして渡す方法を理解しやすくするための例です。
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 []パラメータ