Anonieme methode in Invoke call

Een beetje problemen met de syntaxis waar we een afgevaardigde anoniem willen aanroepen binnen een Control.Invoke.

We hebben een aantal verschillende benaderingen geprobeerd, allemaal zonder resultaat.

Bijvoorbeeld:

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

waar een parameter lokaal is voor deze methode

Het bovenstaande zal resulteren in een compilerfout:

Kan anonieme methode niet converteren naar het type ‘System.Delegate’ omdat het geen gedelegeerd type is


Antwoord 1, autoriteit 100%

Omdat Invoke/BeginInvokeDelegateaccepteert (in plaats van een getypte gemachtigde), moet u de compiler vertellen welk type gemachtigde moet worden aangemaakt ; MethodInvoker(2.0) of Action(3.5) zijn veelvoorkomende keuzes (merk op dat ze dezelfde handtekening hebben); zoals zo:

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

Als je parameters moet doorgeven, dan zijn “vastgelegde variabelen” de manier:

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

(voorbehoud: je moet een beetje voorzichtig zijn bij het gebruik van captures async, maar syncis prima – d.w.z. het bovenstaande is prima)

Een andere optie is om een ​​extensiemethode te schrijven:

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

dan:

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

Je kunt natuurlijk hetzelfde doen met BeginInvoke:

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

Als u C# 3.0 niet kunt gebruiken, kunt u hetzelfde doen met een reguliere instantiemethode, vermoedelijk in een Form-basisklasse.


Antwoord 2, autoriteit 22%

Eigenlijk hoeft u geen gedelegeerd trefwoord te gebruiken. Geef gewoon lambda door als parameter:

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

Antwoord 3, autoriteit 7%

myControl.Invoke(new MethodInvoker(delegate() {...}))

Antwoord 4, autoriteit 6%

U moet een gemachtigdetype maken. Het trefwoord ‘delegeren’ in de anonieme methodecreatie is een beetje misleidend. U creëert geen anonieme afgevaardigde maar een anonieme methode. De methode die u hebt gemaakt, kan worden gebruikt in een gemachtigde. Zoals dit:

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

Antwoord 5, autoriteit 4%

Voor de volledigheid kan dit ook via een Action methode/anonieme methode combinatie:

//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();
});

Antwoord 6, autoriteit 2%

Ik had problemen met de andere suggesties omdat ik soms waarden van mijn methoden wil retourneren. Als je MethodInvoker probeert te gebruiken met retourwaarden, lijkt het niet leuk te vinden. Dus de oplossing die ik gebruik is als volgt (heel blij om een ​​manier te horen om dit beknopter te maken – ik gebruik c#.net 2.0):

   // 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;
        }));
    }

Antwoord 7

Ik gebruik graag Action in plaats van MethodInvoker, het is korter en ziet er schoner uit.

Invoke((Action)(() => {
    DoSomething();
}));
// OR
Invoke((Action)delegate {
    DoSomething();
});

Bijvoorbeeld

// 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";
}

Antwoord 8

Ik heb nooit begrepen waarom dit een verschil maakt voor de compiler, maar dit is voldoende.

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

Bonus: voeg wat foutafhandeling toe, omdat het waarschijnlijk is dat, als u Control.Invokegebruikt vanuit een achtergrondthread, u de tekst / voortgang / ingeschakelde status van een besturingselement bijwerkt en niet’ het maakt niet uit of de besturing al is weggegooid.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}

Other episodes