Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is compilation OK, when I use Invoke method, and not OK when I return Func<int,int> directly?

I don't understand this case:

public delegate int test(int i);  public test Success() {     Func<int, int> f = x => x;     return f.Invoke; // <- code successfully compiled  }  public test Fail() {     Func<int, int> f = x => x;     return f; // <- code doesn't compile } 

Why is compilation OK when I use Invoke method and not OK when I return csharp Func<int,int> directly?

like image 838
Evgeniy Terekhin Avatar asked Mar 09 '20 09:03

Evgeniy Terekhin


People also ask

What will happen if a delegate has a non void return type?

When the return type is not void as above in my case it is int. Methods with Int return types are added to the delegate instance and will be executed as per the addition sequence but the variable that is holding the return type value will have the value return from the method that is executed at the end.

Why delegates why not call methods directly?

If you think of delegates as being similar to interface definitions for a specific type of method, you can start to see why delegates exist. They allow clients of our delegates to ignore all the details of their implementations - even their names!

How do you call a delegate function in C#?

Delegates can be invoke like a normal function or Invoke() method. Multiple methods can be assigned to the delegate using "+" or "+=" operator and removed using "-" or "-=" operator. It is called multicast delegate. If a multicast delegate returns a value then it returns the value from the last assigned target method.

What is a delegate function?

Delegates Overview Delegates are similar to C++ function pointers, but delegates are fully object-oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method. Delegates allow methods to be passed as parameters. Delegates can be used to define callback methods.


1 Answers

There are two things you need to know to understand this behaviour.

  1. All delegates derive from System.Delegate, but different delegates have different types and therefore cannot be assigned to each other.
  2. 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 } 
like image 129
Matthew Watson Avatar answered Sep 20 '22 15:09

Matthew Watson