Why does c# delegate calls accept function names as argument? - c#

I'm trying to understand delegates. when I run the following code:
public delegate void DelegateType1();
public static void callDelegate1(DelegateType1 callback) {
callback();
}
void start() {
callDelegate1(runMe);
}
void runMe() {
Debug.Log("Why?");
}
It outputs 'Why?'.
My question is: If CallDelegate1 takes an argument of type DelegateType1, why does it also accept a function name as argument? Also, is this a bad practice? Every tutorial I've seen online stores the function name in a variable of type DelegateType1.

Paraphrasing:
void f(long l) { }
void g() { f(1); }
My question is: if f takes an argument of type long, why does it also accept an int as argument?
Because there is an implicit conversion from int to long.
My question is: If CallDelegate1 takes an argument of type DelegateType1, why does it also accept a function name as argument?
Because there is an implicit conversion from a method group to a delegate type.
Also, is this a bad practice? Every tutorial I've seen online stores the function name in a variable of type DelegateType1.
The most explicit form is
void start() {
DelegateType1 runMeDelegate = new DelegateType1(runMe);
callDelegate1(runMeDelegate);
}
You can make it less explicit by writing it as a conversion:
void start() {
DelegateType1 runMeDelegate = (DelegateType1) runMe;
callDelegate1(runMeDelegate);
}
You can make it even less explicit by making the conversion implicit:
void start() {
DelegateType1 runMeDelegate = runMe;
callDelegate1(runMeDelegate);
}
And finally, you can get rid of the variable entirely:
void start() {
callDelegate1(runMe);
}
They are all perfectly fine and all do the same thing. The first form is something that code generators typically use, because explicit construction of a delegate type is something that's most widely supported in different languages. The last form is something that programmers tend to write when it's obvious to someone with sufficient C# experience what's going on there.
Tutorials are not focused on programmers with sufficient C# experience, so to make it clearer what's going on, they may choose to use one of the more verbose forms. There is nothing wrong with sticking with that form if it helps you understand, but there is equally nothing wrong with using the shorter form.

Related

Overloading in local methods and lambda

static void Main() {
void TestLocal() => TestLocal("arg");
TestLocal("arg");
}
static void TestLocal(string argument) {
}
In this example, local function has the same name as another method, which I want to overload. But this method is invisible from inside of this function, and even from inside of Main(). The same is for lambdas:
static void Main() {
Action TestLambda = () => TestLambda("arg");
}
static void TestLambda(string argument) {
}
I understand, why lambda hides outer method - because it is a local variable, and local variables always work this way. But I don't see any reason for local functions hide and not overload outer methods - it could be very useful for reducing amout of arguments in local scope, doing some kind of carrying.
Why local functions hide methods?
EDIT:
I can imagine an example where it gets complicated
void Bar(short arg) {
Console.WriteLine("short");
}
void Bar(byte arg) {
Console.WriteLine("byte");
}
void Test() {
void Bar(int arg) {
Console.WriteLine("int");
}
Bar(0);
}
It was already complicated enough with argument type resolution. If they added overloading to local methods, it would be one more stupid task for job interviews and one more huge task for compiler makers. And there are also virtual and new methods...
Why local functions hide methods?
Basically it's introducing the method name into the declaration space inside the method. Within that declaration space, the name only refers to the local method... just as it does for a local variable. I think that's reasonably consistent with the way that names introduced into methods have always worked.
I'd personally advise against trying to do this anyway, as it'll cause confusion, but if you really need to refer to the class method, just make it explicit:
ClassName.TestLocal("arg");
What I do think could be fixed is that local methods can't be overloaded between themselves. You can't write:
void Foo()
{
void Method(int x) {}
void Method(string y) {}
}
This is for a related reason - a method's declaration space can't include the same name twice, whereas a class's declaration space can do so, in terms of method overloading. Maybe the rules will be loosened around this...

My overloaded generic method is not called

I write this piece of code in one of my C# project:
public static class GetAppendReceiver
{
public static AppendReceiver<DataType> Get<DataType>(AppendReceiver<DataType>.DataProcessor processor0, int delayIn = 0)
{
throw new InvalidOperationException();
}
public static AppendReceiver<string> Get(AppendReceiver<string>.DataProcessor processor0, int delayIn = 0)
{
return new StringAppendReceiver(processor0, delayIn);
}
}
public abstract class AppendReceiver<DataType>
{
public delegate void DataProcessor(DataType data);
...
}
AppendReceiver<DataType> is an Abstract class, DataProcessor is a delegate type.
When calling GetAppendReceiver.Get with a string DataProcessor I expect the overloaded function to be called, but I get the InvalidOperationException.
Here is my call:
class ClassA<DataType>
{
public void RegisterAppendReceiver(AppendReceiver<DataType>.DataProcessor receiver)
{
appendReceivers.Add(GetAppendReceiver.Get(receiver, Delay));
}
}
Example of RegisterAppendReceiver call:
myObject.RegisterAppendReceiver(myMethod);
Where myMethod is defined like this:
public void writeMessage(string strMessageIn)
My question is why I get the wrong overload called, and how can I force the language to call the overload I want ?
Thanks for your help !
Eric Lippert answers this question concisely in his article Generics are not Templates
I don't want to copy the entire article. So the relevant point is this:
We do the overload resolution once and bake in the result.
So the C# compiler decides, at the time it compiles RegisterAppendReceiver, which overload of "GetAppendReceiver.Get" it is going to call. Since, at that point, the only thing it knows about DataType is that DataType can be anything at all, it compiles in the call to the overload that takes an AppendReceiver.DataProcessor, not an AppendReceiver.DataProcessor.
By comparison, the C++ compiler does not behave this way. Each and every time a generic call is made, the compiler does the substitution over again. This is one reason C++ compilers are much slower than C# compilers.

The type arguments for method cannot be inferred from the usage. (c#, lambda)

Firstly, I am a complete beginner to advanced level programming. All I have done are tutorials to C++ found on the web. I'm facing this problem at work. I have seen similar queries but nothing has helped me understand.
Please note: I am terrible at terminologies like method, object, interface, etc. So I might have made a mistake somewhere further. I'm slowly learning.
Code Block 1:
public static class DummyClassName
{
public static T DummyTemplateFunc<T>(DummyInterfaceName aaa1, Func<T> action)
{
T DummyVal = action();
// blah blah code
// blah blah code
return val;
}
}
Code Block 2:
public class ClassName2 : blah1 , blah2, blah3
{
public void Method1(string DummyString)
{
DummyClassName.DummyTemplateFunc(_aaa1, ()=>Function1(_arg1, arg2));
}
}
I'll try to explain what's happening to the best of my ability. The second bit of code is used over and over in the program with different Functions (or methods?) in place of Function1. (These functions come from a C++ program linked with this one. I don't know how)
If these functions are of any return type EXCEPT void, the program runs fine.
If a void-return-type function is used, I get the error
"The type arguments for method '****.****.DummyClassName.DummyTemplateName<T>
(****.****.DummyInterfaceName, System.Func<T>)' cannot be inferred from the usage.
Try specifying the type arguments explicitly.'
From what I understand, this is because when a void function is passed it takes the place of T in the first block of code and tries returning 'val'. That's why an error is thrown.
Can somebody help me find a workaround to this? I don't mind defining a completely different class/method specifically to handle void functions. I know which functions are of return type void.
Create another overload, taking Action instead of Func<T>:
public static class DummyClassName
{
public static void DummyTemplateFunc(DummyInterfaceName aaa1, Action action)
{
// you cannot assign result to variable, because it returns void
action();
// I also changed method to return void, so you can't return anything
// return something;
// ofc you can make it return something instead
}
}

c# .net why does Task.Run seem to handle Func<T> differently than other code?

The new Task.Run static method that's part of .NET 4.5 doesn't seem to behave as one might expect.
For example:
Task<Int32> t = Task.Run(()=>5);
compiles fine, but
Task<Int32> t = Task.Run(MyIntReturningMethod);
...
public Int32 MyIntReturningMethod() {
return (5);
}
complains that MyIntReturningMethod is returning the wrong type.
Perhaps I am just not understanding which overload of Task.Run is being called. But in my mind, my lambda code above looks a lot like a Func<Int32>, and MyIntReturningMethod is definitely compatible with Func<Int32>
Any ideas of what's going on?
Michael
(Of course, to get out of the problem, simply say Task.Run((Func<int>)MyIntReturningMethod).)
This has absolutely nothing to do with Task and so on.
One problem to be aware of here is that when very many overloads are present, the compiler error text will focus on just one "pair" of overloads. So that is confusing. The reason is that the algorithm to determine the best overload considers all overloads, and when that algorithm concludes that no best overload can be found, that does not produce a certain pair of overloads for the error text because all overloads may (or may not) have been involved.
To understand what happens, see instead this simplified version:
static class Program
{
static void Main()
{
Run(() => 5); // compiles, goes to generic overload
Run(M); // won't compile!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
static int M()
{
return 5;
}
}
As we see, this has absolutely no reference to Task, but still produces the same problem.
Note that anonymous function conversions and method group conversions are (still) not the exact same thing. Details are to be found in the C# Language Specification.
The lambda:
() => 5
is actually not even convertible to the System.Action type. If you try to do:
Action myLittleVariable = () => 5;
it will fail with error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement. So it is really clear which overload to use with the lambda.
On the other hand, the method group:
M
is convertible to both Func<int> and Action. Remember that it is perfectly allowed to not pick up a return value, just like the statement:
M(); // don't use return value
is valid by itself.
This sort-of answers the question but I will give an extra example to make an additional point. Consider the example:
static class Program
{
static void Main()
{
Run(() => int.Parse("5")); // compiles!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
}
In this last example, the lambda is actually convertible to both delegate types! (Just try to remove the generic overload.) For the right-hand-side of the lambda arrow => is an expression:
int.Parse("5")
which is valid as a statement by itself. But overload resolution can still find a better overload in this case. As I said earlier, check the C# Spec.
Inspired by HansPassant and BlueRaja-DannyPflughoeft, here is one final (I think) example:
class Program
{
static void Main()
{
Run(M); // won't compile!
}
static void Run(Func<int> f)
{
}
static void Run(Func<FileStream> f)
{
}
static int M()
{
return 5;
}
}
Note that in this case, there is absolutely no way the int 5 could be converted into a System.IO.FileStream. Still the method group conversion fails. This might be related to the fact the with two ordinary methods int f(); and FileStream f();, for example inherited by some interface from two different base interfaces, there is no way to resolve the call f();. The return type is not part of a method's signature in C#.
I still avoid to introduce Task in my answer since it could give a wrong impression of what this problem is about. People have a hard time understanding Task, and it is relatively new in the BCL.
This answer has evolved a lot. In the end, it turns out that this is really the same underlying problem as in the thread Why is Func<T> ambiguous with Func<IEnumerable<T>>?. My example with Func<int> and Func<FileStream> is almost as clear. Eric Lippert gives a good answer in that other thread.
This was supposed to be fixed in .Net 4.0, but Task.Run() is new to .Net 4.5
.NET 4.5 has its own overload ambiguity by adding the Task.Run(Func<Task<T>>) method. And the support for async/await in C# version 5. Which permits an implicit conversion from T foo() to Func<Task<T>>.
That's syntax sugar that's pretty sweet for async/await but produces cavities here. The omission of the async keyword on the method declaration is not considered in the method overload selection, that opens another pandora box of misery with programmers forgetting to use async when they meant to. Otherwise follows the usual C# convention that only the method name and arguments in the method signature is considered for method overload selection.
Using the delegate type explicitly is required to resolve the ambiguity.
When you pass a Func<TResult> into a method Run<TResult>(Func<TResult>) you don't have to specify the generic on the methodcall because it can infer it. Your lambda does that inference.
However, your function is not actually a Func<TResult> whereas the lambda was.
If you do Func<Int32> f = MyIntReturningMethod it works. Now if you specify Task.Run<Int32>(MyIntReturningMethod) you would expect it to work also. However it can't decide if it should resolve the Func<Task<TResult>> overload or the Func<TResult> overload, and that doesn't make much sense because its obvious that the method is not returning a task.
If you compile something simple like follows:
void Main()
{
Thing(MyIntReturningMethod);
}
public void Thing<T>(Func<T> o)
{
o();
}
public Int32 MyIntReturningMethod()
{
return (5);
}
the IL looks like this....
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldftn UserQuery.MyIntReturningMethod
IL_0009: newobj System.Func<System.Int32>..ctor
IL_000E: call UserQuery.Thing
(Some of the extra stuff is from LINQ Pad's additions... like the UserQuery part)
The IL looks identical as if you do an explicit cast. So it seems like the compiler does't actually know which method to use. So it doesn't know what cast to create automatically.
You can just use Task.Run<Int32>((Func<Int32>)MyIntReturningMethod) to help it out a bit. Though I do agree that this seems like something the compiler should be able to handle. Because Func<Task<Int32>> is not the same as Func<Int32>, so it doesn't make sense that they would confuse the compiler.
Seems like an overload resolution problem. The compiler can't tell which overload you're calling (because first it has to find the correct delegate to create, which it doesn't know because that depends on the overload you're calling). It would have to guess-and-check but I'm guessing it's not that smart.
The approach of Tyler Jensen works for me.
Also, you can try this using a lambda expression:
public class MyTest
{
public void RunTest()
{
Task<Int32> t = Task.Run<Int32>(() => MyIntReturningMethod());
t.Wait();
Console.WriteLine(t.Result);
}
public int MyIntReturningMethod()
{
return (5);
}
}
Here's my stab at it:
public class MyTest
{
public void RunTest()
{
Task<Int32> t = Task.Run<Int32>(new Func<int>(MyIntReturningMethod));
t.Wait();
Console.WriteLine(t.Result);
}
public int MyIntReturningMethod()
{
return (5);
}
}

What function will a delegate point two if there is more than one method which meets the delegate criteria?

A delegate is a function pointer. So it points to a function which meets the criteria (parameters and return type).
This begs the question (for me, anyway), what function will the delegate point to if there is more than one method with exactly the same return type and parameter types? Is the function which appears first in the class?
Thanks
The exact method is specified when you create the Delegate.
public delegate void MyDelegate();
private void Delegate_Handler() { }
void Init() {
MyDelegate x = new MyDelegate(this.Delegate_Handler);
}
As Henk says, the method is specified when you create the delegate. Now, it's possible for more than one method to meet the requirements, for two reasons:
Delegates are variant, e.g. you can use a method with an Object parameter to create an Action<string>
You can overload methods by making them generic, e.g.
static void Foo() {}
static void Foo<T>(){}
static void Foo<T1, T2>(){}
The rules get quite complicated, but they're laid down in section 6.6 of the C# 3.0 spec. Note that inheritance makes things tricky too.
So it points to a function which meets the criteria (parameters and return type).
Nope.
To add some background to Henk's Answer:
Just like int x is an variable which can contain integers, A delegate is a variable which can contain functions.
It points to whatever function you tell it to point to.
EG:
// declare the type of the function that we want to point to
public delegate void CallbackHandler(string); //
...
// declare the actual function
public void ActualCallbackFunction(string s){ ... }
...
// create the 'pointer' and assign it
CallbackHandler functionPointer = ActualCallbackFunction;
// the functionPointer variable is now pointing to ActualCallbackFunction

Categories

Resources