There are two things you need to know to understand this behaviour.
- All delegates derive from
System.Delegate
, but different delegates have different types and therefore cannot be assigned to each other.
- The C# language provides special handling for assigning a method or lambda to a delegate.
Because different delegates have different types, that means you can't assign a delegate of one type to another.
For example, given:
delegate void test1(int i);
delegate void test2(int i);
Then:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
The first line above compiles OK because it is using the special handling for assigning a lambda or a method to a delegate.
In fact, this line is effectively rewritten like this by the compiler:
test1 a = new test1(Console.WriteLine);
The second line above does not compile because it is trying to assign an instance of one type to another incompatible type.
As far at the types go, there is no compatible assignment between test1
and test2
because they are different types.
If it helps to think about it, consider this class hierarchy:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
The following code will NOT compile, even though Test1
and Test2
derive from the same base class:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
This explains why you can't assign one delegate type to another. That's just the normal C# language.
However, the crucial thing is to understand why you're allowed to assign a method or lambda to a compatible delegate. As noted above, this is part of the C# language support for delegates.
So finally to answer your question:
When you use Invoke()
you are assigning a METHOD call to the delegate using the special C# language handling for assigning methods or lambdas to a delegate rather than trying to assign an incompatible type - hence it compiles OK.
To be completely clear, the code which compiles in your OP:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Is actually converted conceptually to something like:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Whereas the failing code is attempting to assign between two incompatible types:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}
delegate void test1(int i);
anddelegate void test2(int i);
– Engineer