4

I have taken a look at this Question diference between delegate and action

and I'm still wondering why can I pass lambda expressions to methods that accept Action type parameters
whereas I can not pass lambda expressions to methods that accept Delegate type parameters
I have this Print method, I'm going to refer to it using action and Delegate

public static void Print()
{
    Console.WriteLine("Printing ..");
}

I created these two methods which will invoke Print method as you can see the first one has Action type parameter and the second one has Delegate type Parameter these parameterss will refer to the method "Print"

public static void ActionParamMethod(Action DAction)
{
    DAction();
}
public static void DelegateParamMethod(Delegate SomeDelegate)
{

}

I'm going to pass lambda expressions to these methods

public static void SomeHowMethod()
{
    DelegateParamMethod(() => Print());
    ActionParamMethod(() => Print());
}

when I try to pass lambda expression to the method which accept Delegate parameter I get this error

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type

why it's not delegate type and Action is delegate type ?
why I can pass lambda expressions to methods that accept Action parameters, but I can't pass lambda expressions to methods that accept Delegate parameters?

Rickless
  • 1,377
  • 3
  • 17
  • 36

4 Answers4

8

Lambdas need to infer the actual type of the delegate used based on context. When attempting to use a lambda in a context where a Delegate is expected the lambda's inference algorithm cannot determine which specific type of delegate it should be. It would be like trying to construct an instance of an interface; you wouldn't know which implementation to choose.

Servy
  • 202,030
  • 26
  • 332
  • 449
7

The reason is that lambda expressions do not have a type in C# unless you cast them to a concrete type.

Delegate type is the base class for all delegates.It's an abstract class. Unless you specify an actual delegate type like Action or Func, you can't pass a lambda expression as Delegate. It's like you can't instantiate an abstract class but you can pass a class that implements it as a parameter. If you cast your lambda to any delegate type it will work as expected:

DelegateParamMethod((Action<string>)(x => Console.WriteLine(x));

The reason why your first method works without specifying type is because the expression can be converted to Action, otherwise it wouldn't be valid for the same reason why this expression is not valid:

var x = () => Print("Hello world");
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • does that mean lambda expression can be implicitly converted to Action but can not be implicitly converted to Delegate and I should explicit cast them into Action type if the parameter of type Delegate? – Rickless Jan 08 '15 at 16:40
1

The problem is that you aren't providing the type of delegate you want to invoke. You are looking for something like:

DelegateParamMethod((Action)(() => Print()));
James C. Taylor IV
  • 599
  • 10
  • 24
0

You should not refer to Delegate in your code, it is the base class for delegates but is not meant to be used like you are doing here.

Instead you should choose a delegate type (like your Action example) and use it as the parameter.

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • 1
    While one should certainly be wary of using `Delegate`, it does have its uses. If you really want to be able to accept any delegate regardless of its signature then that's what you need to use. Appropriate uses of it are certainly rare, but they do exist. Also note that this doesn't actually answer the question. It should be a comment at most. – Servy Jan 08 '15 at 16:31
  • there are many uses of Delegate in many methods like BeginInvoke for forms and controls but to be honest I do not know why it's being used – Rickless Jan 08 '15 at 16:35
  • 1
    @Servy: I prefer absolutes when clarifying points like this. Peppering everything with "usually" tends to make the point vague. If you don't understand the difference between a delegate and a `Delegate` then it is safe to say "never use the latter" as it will be a long time before you need to. – Guvante Jan 08 '15 at 16:36
  • Teaching people incorrect information that they only need to unlearn latter makes the learning process longer and harder. – Servy Jan 08 '15 at 16:38
  • 1
    @Servy: What incorrect information? Unless you are doing multi-threaded Windows Forms logic you probably shouldn't be using `Delegate` (it is the easiest way to get to the UI thread). In the majority of cases accepting an `Action` and requiring a lambda wrapper will solve your problem in a much more direct fashion than trying to use a raw `Delegate`. – Guvante Jan 08 '15 at 16:39
  • 1
    @MadMass: Windows Forms requires certain methods be called from the UI thread since they aren't thread safe. There are ways to use BeginInvoke to ensure that those methods are called from the right thread. However you can always get a `Delegate` from an `Action` or any other delegate as it is the base class, so you are never more than a cast away. – Guvante Jan 08 '15 at 16:41
  • 1
    @Guvante In many cases, yes, it will. But not all cases using delegates involve the signature of the delegate to be known at compile time. In such cases `Delegate` must be used. – Servy Jan 08 '15 at 16:42