3

WinForm コントロールを呼び出すこの一般的な関数があります。

public static void Invoke(this Control c, Action action)
{
    if (c.InvokeRequired)
        c.TopLevelControl.Invoke(action);
    else
        action();
}

無意味なことを防ぐために、より厳しい制約を加えることで、より良いものにすることを考えています。

button1.Invoke(() => list.Add(1));

また、次のような冗長な入力が存在する可能性があります。

button1.Invoke(() => button1.Hide());

すでに is を指定しているためthisですbutton1

だから私はそれを作った:

public static void Invoke<T>(this T c, Action<T> action) where T : Control
{
    if (c.InvokeRequired)
        c.TopLevelControl.Invoke(action);
    else
        action(c);
}

今、私は電話する必要があります。

button1.Invoke((c) => c.Hide());

また

button1.Invoke((c) => button1.Hide());

それでも、必要以上のタイピングがあるように感じます。thisisを指定している場合、ラムダ式では、どこで操作するかを伝えるためにダミー変数を再度button1指定したくありません。cとにかくこれをもう一度短くすることはできますか?おそらく好き

button1.Invoke(Hide);

また

button1.Hide.Invoke();

C#で?

4

5 に答える 5

2

私は一緒に行きます:

public static void Invoke<T>(this T c, Action<T> action) where T : Control
{
    if (c.InvokeRequired)
        c.TopLevelControl.Invoke(action);
    else
        action(c);
}

button.Invoke(c => c.Hide());

これは、最もクリーンで (アクションを実行するために最初に指定されたボタンが返されます)、最も安全です ( button12 回指定する必要はありません...ラムダのパラメーターとして返されます)。 . これはエレガントな構文だと思います。

于 2012-12-25T05:08:47.597 に答える
2

最初に言っておきますが、あなたはこれを考えすぎているかもしれません。短いコードは素晴らしいことですが、コードを読もうとする人にとって混乱し始めるポイントがあります。

さて、あなたの最初の提案:

button1.Invoke(Hide);

あなたがそれを作るなら、うまくいくかもしれません:

button1.Invoke(button1.Hide); 

そうしないと、コンパイラはメソッド Hide() を探す場所がわからないためです。たとえば、このコードのすべてが次のような派生クラスにある場合など、奇妙な動作を引き起こす可能性さえあります。

class A : Control {
    public A() {
         Button button1=new Button();
         button1.Invoke(Hide);
    }
}

これでコンパイルできますが、Hide() メソッドは、ボタンではなく、コントロール全体の Hide() メソッドになります。これを達成する方法は簡単です:

public static void Invoke(this Control c, Action action) {
    c.Invoke(action);
}

後者の方法:

button1.Hide().Invoke();

拡張メソッドを追加しなくても機能する場合は、次のようにするだけです。

((Action)button1.Hide).Invoke();

もちろん、これは Hide() メソッドが現在のスレッドで呼び出されることを意味しますが、これはおそらくあなたが望むものではありません。だからそれを作る:

((Action)button1.Hide).Invoke(button1);
public static void Invoke(this Action action, Control c) {
    c.Invoke(action);
}

長い回答で申し訳ありませんが、お役に立てば幸いです。

于 2012-12-24T10:41:32.920 に答える
1

button1.Invoke(Hide);C# の構文制限のように、またはC# の構文制限のために、これを行うことは絶対にできませんbutton1.Hide.Invoke();

ただし、IntelliSense をあきらめても構わない場合は、もう少し短くすることができます。欠点として、通常はコンパイル時に検出および修正できるいくつかのバグ (タイプミスやパラメーターの不一致など) が実行時エラーになります。受け入れられる場合もあれば、受け入れられない場合もあります。

先を見越して、使用例を次に示します。

button1.Invoke("Hide");

また

button1.Invoke("ResumeLayout", true);

解決:

internal static class ExtensionMethods
{
    internal static object Invoke<TControl>(this TControl control,
        string methodName, params object[] parameters)
        where TControl : Control
    {
        object result;

        if (control == null)
            throw new ArgumentNullException("control");

        if (string.IsNullOrEmpty(methodName))
            throw new ArgumentNullException("methodName");

        if (control.InvokeRequired)
            result = control.Invoke(new MethodInvoker(() => Invoke(control,
                methodName, parameters)));
        else
        {
            MethodInfo mi = null;

            if (parameters != null && parameters.Length > 0)
            {
                Type[] types = new Type[parameters.Length];
                for (int i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i] != null)
                        types[i] = parameters[i].GetType();
                }

                mi = control.GetType().GetMethod(methodName,
                    BindingFlags.Instance | BindingFlags.Public,
                    null,  types, null);
            }
            else
                mi = control.GetType().GetMethod(methodName,
                    BindingFlags.Instance | BindingFlags.Public);

            if (mi == null)
                throw new InvalidOperationException(methodName);

            result = mi.Invoke(control, parameters);
        }

        return result;
    }
于 2012-12-24T11:08:59.493 に答える