Anonymous methods and delegates

13,906

Solution 1

The Delegate class is the base class for delegate types. However, only the system and compilers can derive explicitly from the Delegate class or from the MulticastDelegate class. It is also not permissible to derive a new type from a delegate type. The Delegate class is not considered a delegate type; it is a class used to derive delegate types. Source -- MSDN

Hence the need for the explicit cast to a derived-from-Delegate type. You'd encounter this particular compiler error when you pass an anonymous method for a parameter of System.Delegate type - fortunately this is a rare scenario. That's just too much flexibility.

delegate void MyDelegate();

  static void DoSomething_Flexible(Delegate d)
  {   d.DynamicInvoke();      }
  static void DoSomething_Usable(MyDelegate d)
  {   d();      }
  static void Main(string[] args)
  {
     // requires explicit cast else compile error Error "Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type    
     DoSomething_Flexible((MyDelegate) delegate { Console.WriteLine("Flexible is here!"); });  

     // Parameter Type is a .NET Delegate, no explicit cast needed here. 
     DoSomething_Usable(delegate { Console.WriteLine("Usable is here!"); });
  }

More on this at this page by Ian Griffith. (See the paras after the Notes header)

Solution 2

You need to tell the compiler what type of delegate to create, since Invoke (etc) just take Delegate (rather than something more specific).

To apply to the largest audience, MethodInvoker is a handy delegate type

BeginInvoke((MethodInvoker) delegate(...) {...});

However... BackgroundWorker.ProgressChanged fires on the UI thread automatically - so you don't even need this.

Solution 3

Most of the time you're dealing with either a parameterless delegate or a predicate in these cases. The easiest way of sorting this is by casting your anonymous method directly to either Action or Predicate respectively; you just don't need to create a custom delegate type for simple things like that.

So you'll have something like

BeginInvoke((Action)delegate(){YourCode.DoSomething();});

or

BeginInvoke((Predicate)delegate(object yourParameter){return YourCode.IsTheParameterSomething(yourParameter)});

HTH

Share:
13,906
Mez
Author by

Mez

Updated on June 04, 2022

Comments

  • Mez
    Mez almost 2 years

    I try to understand why a BeginInvoke method won't accept an anonymous method.

    void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (InvokeRequired)
        {
            //Won't compile
            BeginInvoke(delegate(object sender, ProgressChangedEventArgs e) 
            { bgWorker_ProgressChanged(sender, e); });
        }
    
        progressBar1.Increment(e.ProgressPercentage);
    }
    

    It tells me 'cannot convert from 'anonymous method' to 'System.Delegate' while when I cast the anonymous method to a delegate it does work ?

    BeginInvoke((progressDelegate)delegate { bgWorker_ProgressChanged(sender, e); });
    
  • Peter Wone
    Peter Wone over 11 years
    Nice answer, but I'm not sure I'd describe SomeControl.BeginInvoke(Delegate method, param object[] args) as rare.
  • Gishu
    Gishu over 11 years
    @PeterWone - :). I'd suggest using a BackgroundWorker instance to handle UI Thread affinity. You can't do anything about existing third party methods written in this manner - you'd need to mark with a small (Action) cast