Invoke çağrısında anonim yöntem


131

Bir Control.Invoke içinde isimsiz olarak bir temsilci çağırmak istediğimiz sözdizimiyle ilgili biraz sorun yaşıyoruz.

Bir takım farklı yaklaşımlar denedik, hepsi boşuna.

Örneğin:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

someParameter bu yöntem için yereldir

Yukarıdakiler bir derleyici hatasıyla sonuçlanacaktır:

Bir temsilci türü olmadığından anonim yöntem 'System.Delegate' türüne dönüştürülemiyor

Yanıtlar:


221

Çünkü Invoke/ BeginInvokekabul eder Delegate(yazılı bir temsilci yerine), derleyiciye ne tür bir temsilci oluşturacağını söylemeniz gerekir; MethodInvoker(2.0) veya Action(3.5) ortak seçeneklerdir (aynı imzaya sahip olduklarını unutmayın); böyle:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

Parametreleri iletmeniz gerekiyorsa, "yakalanan değişkenler" şu şekilde olur:

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(uyarı: eşzamansız yakalamalar kullanıyorsanız biraz dikkatli olmanız gerekir , ancak eşitleme iyidir - yani yukarıdakiler iyidir)

Diğer bir seçenek de bir uzatma yöntemi yazmaktır:

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

sonra:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

Elbette aynı şeyi aşağıdakilerle de yapabilirsiniz BeginInvoke:

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

C # 3.0'ı kullanamıyorsanız, aynı şeyi normal bir örnek yöntemiyle, muhtemelen Formtemel sınıfta yapabilirsiniz.


Bu cevapta ilk çözümünüze parametreleri nasıl aktarabilirim? Bu çözümü kastettim: control.Invoke ((MethodInvoker) delege {this.Text = "Merhaba";});
uzay95

1
Uzantı Yöntemi, Neden Eylem için Açık bir dönüşüm yapmak zorunda kalmadan çağrılır?
P. Brian.Mackey

Çünkü derleyici bunu kullanımdan çıkarabilir.
RoboJ1M

1
Form.Load += Loader()Form.Load += new EventHandler(Loader())
Eskisinin

49

Aslında delege anahtar kelimesini kullanmanıza gerek yoktur. Lambda'yı parametre olarak geçirmeniz yeterlidir:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));


13

Temsilci türü oluşturmanız gerekir. Anonim yöntem oluşturmadaki 'temsilci' anahtar kelimesi biraz yanıltıcıdır. Anonim bir temsilci değil, anonim bir yöntem oluşturuyorsunuz. Oluşturduğunuz yöntem bir temsilcide kullanılabilir. Bunun gibi:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));

8

Eksiksizlik adına, bu aynı zamanda bir Eylem yöntemi / anonim yöntem kombinasyonu aracılığıyla da gerçekleştirilebilir:

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});

Invoke((Action) Process);en iyi cevap, teşekkürler!
Jinjinov

5

Yöntemlerimden bazen değerler döndürmek istediğim için diğer önerilerde sorun yaşadım. MethodInvoker'i dönüş değerleriyle kullanmaya çalışırsanız, hoşunuza gitmiyor. Öyleyse kullandığım çözüm şöyle (bunu daha kısa ve öz hale getirmenin bir yolunu duyduğuma çok sevindim - c # .net 2.0 kullanıyorum):

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }

1

MethodInvoker yerine Action kullanmayı seviyorum, daha kısa ve daha temiz görünüyor.

Invoke((Action)(() => {
    DoSomething();
}));

// OR

Invoke((Action)delegate {
    DoSomething();
});

Örneğin.

// Thread-safe update on a form control
public void DisplayResult(string text){
    if (txtResult.InvokeRequired){
        txtResult.Invoke((Action)delegate {
            DisplayResult(text);
        });
        return;
    }

    txtResult.Text += text + "\r\n";
}

0

Bunun derleyici için neden bir fark yarattığını asla anlamadım, ancak bu yeterli.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

Bonus: Bir miktar hata işleme ekleyin, çünkü muhtemelen Control.Invokebir arka plan iş parçacığından kullanıyorsanız , bir kontrolün metnini / ilerleme / etkin durumunu güncelliyorsunuz ve kontrolün zaten atılmış olup olmadığını umursamıyorsunuz.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.