2

私は次のことを頻繁に行っていますが、副作用があるかどうかはわかりませんが、WinForms C# アプリで次のことを検討してください。(コードを入力しているので、何かをコピーして貼り付けるのではなく、エラーがあればお許しください)

int a = 1;
int b = 2;
int c = 3;
this.Invoke((MethodInvoker)delegate()
{
    int lol = a + b + c;
});

何か問題がありますか?それとも遠回りするべきか>_<

int a = 1;
int b = 2;
int c = 3;
TrippleIntDelegate ffs = new TrippleIntDelegate(delegate(int a_, int b_, int c_)
{
   int lol = a_ + b_ + c_;
});

this.Invoke(ffs);

違いは、ローカル変数を使用する代わりにパラメーターが渡されることです。かなり甘い .net マジックです。一度リフレクターを見て、それらの変数を保持するためのまったく新しいクラスを作成したと思います。

それで、それは問題ですか?怠けてもいいですか?

編集:注意してください、明らかに戻り値を気にしないでください。それ以外の場合は、ローカル変数を渡さずに使用できますが、独自の型付きデリゲートを使用する必要があります。

4

4 に答える 4

3

使い方によっては、特に違いはありません。ただし、最初のケースでは、匿名メソッドが変数をキャプチャしているため、何をしているのかわからないと、かなり大きな副作用が生じる可能性があります。例えば ​​:

// No capture :
int a = 1;
Action<int> action = delegate(int a)
{
    a = 42; // method parameter a
});
action(a);
Console.WriteLine(a); // 1

// Capture of local variable a :
int a = 1;
Action action = delegate()
{
    a = 42; // captured local variable a
};
action();
Console.WriteLine(a); // 42
于 2010-02-25T02:26:57.073 に答える
1

まあ、他のすべての答えは、マルチスレッドのコンテキストとその場合に発生する問題を無視しているようです。実際に WinForms からこれを使用している場合、最初の例で例外がスローされる可能性があります。デリゲートから参照しようとしている実際のデータに応じて、コードが実際に呼び出されるスレッドは、閉じたデータにアクセスする権利を持っている場合と持っていない場合があります。

一方、2 番目の例では、実際にはパラメーターを介してデータを渡します。これにより、Invoke メソッドはスレッドの境界を越えてデータを適切にマーシャリングし、厄介なスレッド化の問題を回避できます。たとえば、バックグラウンド ワーカーから Invoke を呼び出している場合は、2 番目の例のようなものを使用する必要があります (ただし、Action<T, ...> および Func<T, ...> デリゲートを使用することを選択します)。新しいものを作成するのではなく可能です)。

于 2010-02-25T02:58:22.133 に答える
1

実行が遅延していることを理解している限り、ローカル変数を渡すことに問題はありません。これを書くと:

int a = 1;
int b = 2;
int c = 3;
Action action = () => Console.WriteLine(a + b + c);
c = 10;
action();  // Or Invoke(action), etc.

この出力は、6 ではなく 13 になります。これは、トーマスが言ったことに対応すると思います。デリゲートでローカルを読み取る場合、アクションが宣言されたときではなく、アクションが実際に実行されたときに変数が保持する値を使用します。変数が参照型を保持し、デリゲートを非同期的に呼び出すと、興味深い結果が得られる可能性があります。

それ以外にも、ローカル変数をデリゲートに渡す正当な理由がたくさんあります。特に、スレッドコードを簡素化するために使用できます。よそよそしくしない限り、まったく問題ありません。

于 2010-02-25T02:52:46.857 に答える
0

スタイルの観点から、私はパラメーターを渡すバリアントを選択します。任意の種類のアンビエントを取る代わりに引数を渡す方がはるかに簡単な意図を表現しています (また、テストも容易になります)。つまり、これを行うことができます:

public void Int32 Add()
{
    return this.Number1 + this.Number2
}

しかし、それはテスト可能でも明確でもありません。パラメータを取得するシグは、メソッドが何をしているのか他の人にとってはるかに明確です...それは2つの数字を追加しています:数字の任意のセットなどではありません。

とにかくrefを介して使用され、明示的に「返される」必要がないコレクションのようなparmsでこれを定期的に行います。

public List<string> AddNames(List<String> names)
{
    names.Add("kevin");
    return names;
}

names コレクションは ref によって渡されるため、明示的に返す必要はありませんが、メソッドがリストを取得して追加し、それを返すことは、私には明らかです。この場合、このように sig を記述する技術的な理由はありませんが、私にとっては、明快さ、したがって保守性に関する限り正当な理由があります。

于 2010-02-25T02:34:36.613 に答える