I've been reading the MSDN page on delegates and they seem straightforward. Then I was looking at some code that uses them and I saw this:
public delegate void NoArguments();
public NoArguments Refresh = null;
Refresh = new NoArguments( Reset );
It's that third line that confuses me. How can you new a delegate? It is not an object, it's a method, or rather a delegate to a method. According to the example on the MSDN page, creating an instance of a delegate is through simple assignment, not allocaiton. Furthermore, why is the new for the delegate taking a parameter, Reset, when the delegate declaration takes no parameters?
The delegate keyword indicates that what follows is essentially a function signature, so therefore, Refresh becomes kind of like a pointer to a function that takes no arguments. However, to assign something to the Refresh pointer, you have to give it a function to point to. In this case, it's the Reset function. And further, the Reset function must take no arguments.
In addition, the syntax:
Refresh = Reset;
is also valid, and is just syntactic sugar for the more formal syntax:
Refresh = new NoArguments(Reset);
in both cases, you could then execute the Reset function by calling Refresh:
Refresh();
Note, however, that if you execute Refresh() without it having been assigned, then you could generate an exception. The way to prevent this would be to check it against null:
if (Refresh != null) Refresh();
else {
// Refresh was never assigned
}
You may think delegate is like a function type:
Declare type, function returns void and have no arguments:
public delegate void NoArguments();
Declare variable of given type and initialize it:
public NoArguments Refresh = null;
Assign new object to your variable. Object is actually a function Reset, which must have the same signature as your delegate:
Refresh = new NoArguments( Reset );
UPDATE:
You may review the following link for more details: C# Delegates
Delegate is "delegate to a method", but also an object. If you look at NoArguments in any decompiler, you will see it is actually a class inheriting from MulticastDelegate, with several methods (Invoke, BeginInvoke, EndInvoke).
For historical reasons, C# allows you to create instances of that class using new NoArguments(method). However in modern versions it also supports a shortcut notation method that does the same thing. In both cases, you actually do have an object of type NoArguments in Refresh.
Related
I'm attempting to store a List of methods inside a List<dynamic>to create a part of my Quest system. I've never used Lists and I don't exactly know what the dynamickeyword does, so I'm having problems understanding.
To begin with, I've created a test function, and I'm trying to store it inside the List<dynamic>, and then output what the Test function returns through the console (Debug.Log()). Here's the code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Quests : MonoBehaviour
{
public List<dynamic> activeQuests = new List<dynamic>();
void Start()
{
activeQuests.Add(Test());
Debug.Log(activeQuests[0]);
}
public bool Test()
{
return true;
}
}
A red line appears under Debug.Log(activeQuests[0]); and the error message shown as below -
"One or more types required to compile a dynamic expression cannot be
found. Are you missing a reference?"
How do I make this work?
Edit: I'm also looking for a way to add overload methods to each of these functions with parameters.
If the method are always parameter less I suggest to use this:
public List<System.Action> activeQuests = new List<System.Action>();
// usage
activeQuests.Add(Test)
Maybe a return value is needed. Then you should go with any Systen.Func<T ...> delegate.
public List<System.Func<bool>> activeQuests = new List<System.Func<bool>>();
// usage
activeQuests.Add(Test)
One solution is to not use dynamic. If you can make your quest methods conform to the same signature, like bool Test() as you have there, then you can store it using strong typing just fine.
Func<bool> represents a delegate that takes no parameters and returns a bool. So make a List<Func<bool>> and you'll have a list of functions that take no parameters and return a bool.
A mistake you're making is activeQuests.Add(Test());. This calls Test then adds the return value to activeQuests, but you want to add Test itself to activeQuests. Get rid of those () so you don't call the function.
Edit: If you want to pass parameters to your functions, check out the other versions of Func<>. If you add more types, you start adding parameters. For example, Func<int, bool> is a delegate that takes one int parameter and returns a bool.
If all your delegates are in a single list, it makes sense to give them all the same signature. This way you can call any of them with strong typing. For example, you could call each function in activeQuests like this:
foreach (Func<int, bool> questFunction in activeQuests)
{
questFunction(5);
}
Similarly, check out Action and Action<...>. When you add more generic parameters, you're adding parameters the delegate takes. But Action delegates don't have return values, which might fit what you really want better. Everything else works exactly the same.
putting () parenthesys after a method name calls the method, it does not reference the method.
So with this logic: activeQuests.Add(Test()); is actually calling Test() and looking for a return value to pass into activeQuests. Instead, you want to send a reference to the Test() method into activeQuests, so you have to pass it without the parenthesys, i.e. activeQuests.Add(Test);. But activeQuests needs to be a list of methods (Action<...> or Func<...>), not a list of dynamic.
I'm going through an MVC tutorial and see this line of code at the beginning of a function:
private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
After testing it out, I can see that the function works, but I do not understand how the function parameter works. What does object selectedDepartment = null do?
I have done a general internet search and have not yet been able to locate an answer.
I guess my question really has two facets:
What does the = null portion of the parameter do?
Is it something that can be done but not necessarily should be done?
It means that that parameter will be null, unless you decide to pass something. So in other words, its optional.
It can be done, and there is nothing wrong with it. Its pretty common practice.
It means that you can call
PopulateDepartmentsDropDownList()
or
PopulateDepartmentsDropDownList("something")
both because compiler will convert the first one to
PopulateDepartmentsDropDownList(null)
This feature is called Optional Arguments
I suggest you to read this blog post
the = null is the default value of the parameter, it is the functional equivalent as if you had
private void PopulateDepartmentsDropDownList()
{
PopulateDepartmentsDropDownList(null);
}
private void PopulateDepartmentsDropDownList(object selectedDepartment)
{
//Your code here.
}
So if you can call the function with no parameters PopulateDepartmentsDropDownList() it will call the 1 perameter version and pass in null.
This sets the argument to a default value (if not provided) and prevents a compile time error if the argument is not provided. See:
Setting the default value of a C# Optional Parameter
Basically this argument is now optional so you can call the function in either of these two ways:
PopulateDepartmentsDropDownList() //selectedDepartment will be set to null as it is not provided
OR
PopulateDepartmentsDropDownList(myObject) //selectedDepartment will become myObject
Quick question.
In the second example on this documentation page (the second code block, featuring a method called CompareDinosByLength), the Sort method is called as such:
dinosaurs.Sort(CompareDinosByLength);
Why is it that the Sort method didn't need an explicitly declared delegate, as I would have thought by reading the Delegate documentation? Before I found that example, I was attempting to do it like so:
delegate int CompareDinosDel(string first, string second);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
But I kept getting errors related to the delegate / delegate method not being proper Comparers.
Shouldn't both work?
Why is it that the Sort method didn't need an explicitly declared delegate?
C# permits a method group -- that is, a method which is named without having the (...) argument list to invoke it -- to be used in a context where a delegate is expected. The compiler performs overload resolution on the method group as though the method group had been invoked with arguments of the types of the delegate's formal parameters. This determines which method of the method group should be used to create the delegate.
This overload resolution process can sometimes lead to unusual situations involving method type inference when the method group is undergoing overload resolution to a delegate type which is a formal parameter type of a generic method; Sort, fortunately is not a generic method, so these oddities do not come into play.
This feature was added to C# 2.0; before that a method group had to be converted to a delegate via
new MyDelegate(MyMethod)
I keep getting errors related to the delegate / delegate method not being proper Comparers. Shouldn't both work?
Unfortunately, no. C# does not have structural identity on delegate types. That is:
delegate void Foo();
delegate void Bar();
...
Foo foo = ()=>{};
Bar bar = foo; // ERROR!
Even though Foo and Bar are structurally identical, the compiler disallows the conversion. You can however use the previous trick:
Bar bar = foo.Invoke;
This is equivalent to
Bar bar = new Bar(foo.Invoke);
However the new bar has as its action to invoke foo; it goes through a level of indirection.
This feature does make some sense.
Reason one:
You don't expect structural identity to work in other places:
struct Point { int x; int y; ... }
struct Pair { int key; int value; ... }
....
Point point = whatever;
Pair pair = point; // ERROR
Reason two:
You might want to say:
delegate int PureMethod(int);
And have a convention that PureMethod delegates are "pure" -- that is, the methods they represent do not throw, always return, return a value computed only from their argument, and produce no side effects. It should be an error to say
Func<int, int> f = x => { Console.WriteLine(x); return x+1; };
PureMethod p = f;
Because f is not pure.
However in hindsight people do not actually make semantics-laden delegates. It is a pain point that a value of type Predicate<int> cannot be assigned to a variable of type Func<int, bool> and vice versa.
If we had to do it all over again, I suspect that delegates would have structural identity in the CLR.
Finally, I note that VB is much more forgiving about inter-assigning mixed delegate types; it automatically builds an adapter delegate if it needs to. This can be confusing because sometimes it looks like referential identity is maintained when in fact it is not, but this is in keeping with the VB philosophy of "just make my code work".
dinosaurs.Sort(CompareDinosByLength);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
Shouldn't both work?
No, because you are passing two very different things into those two function calls.
The key here is to recognize that, in both cases, what you actually pass into the method is a delegate. In the first case, the compiler is implicitly creating a delegate of the correct type for you, even though you didn't explicitly ask it to. In the second case, you're making your own delegate, but it's the wrong type, so that attempt will fail.
Starting with .NET 2.0, the C# compiler allow you to skip explicitly create delegates in many situations. If you use a method name in a context where a delegate is expected, and the compiler can verify that the method signature and delegate signature match, it will implicitly construct a delegate instance using the method. That is, instead of doing this (the "old" way)
this.SubmitButton.Click += new System.EventHandler(this.SubmitButton_Click);
You can now do this:
this.SubmitButton.Click += this.SubmitButton_Click;
Visual Studio itself will still generate the older syntax, I assume because it still works and because it's not worth the developer's time to go messing around with it for very little benefit. However, most popular code analysis tools will flag the redundant delegate creation if you use it in your own code.
This same technique works anywhere you have a method (technically a "method group", since one method name can refer to more than one overload), and you assign it to a variable of a delegate type. Passing a method as a parameter into another method is the same type of assignment operation: you are "assigning" the actual parameter at the call site to the formal parameter in the method body, so the compiler does the same thing. In other words, the following two method calls do exactly the same thing:
dinosaurs.Sort(CompareDinosByLength);
dinosaurs.Sort(new Comparison<string>(CompareDinosByLength));
Your unsuccessful attempt to make a delegate, on the other hand, did something slightly different:
dinosaurs.Sort(new CompareDinosDel(CompareDinosByLength));
This time, you told the compiler exactly what kind of delegate you wanted, but that's not the kind of delegate that the method expected. In general, the compiler isn't going to try to second guess what you told it do to; if you ask it to do something that looks "fishy", it will produce an error (in this case, a type mismatch error).
This behavior is similar to what would happen if you tried to do this:
public class A
{
public int x;
}
public class B
{
public int x;
}
public void Foo(A a) { }
public void Bar()
{
B b = new B();
this.Foo(b);
}
In this case, A and B are two distinct types, even though their "type signature" is exactly the same. Any line of code that works on an A will also work equally well on a B, but yet, we cannot use them interchangeably. Delegates are types like any other types, and C#'s type safety rules require that we use the correct delegate types where we need them, and can't get away with just using a close enough type.
The reason this is a good thing is because a delegate type may have a lot more meaning that just it's technical components would imply. Like any other data type, when we create delegates for our applications, we usually apply some kind of semantic meaning to those types. We expect, for example, that if we have a ThreadStart delegate, that it's going to be associated with a method that runs when a new thread starts. the delegate's signature is about as simple as you get (no parameters, no return value) but the implication behind the delegate is very important.
Because of that, we generally want the compiler to tell us if we try to use the wrong delegate type in the wrong place. More often than not, that's probably a sign that we are about to do something that may compile, and even run, but is likely to do the wrong thing. That's never something you want from your program.
While all that is true, it's also true that often times you really don't want to assign any semantic meaning to your delegates, or else, the meaning is assigned by some other part of your application. Sometimes you really do just want to pass around an arbitrary piece of code that has to run later. This is very common with functional-style programs or asynchronous programs, where you get things like continuations, callbacks, or user-supplied predicates (look at the various LINQ methods, for example). .NET 3.5 and onward supply a very useful set of completely generic delegates, in the Action and Func family, for this purpose.
Consider the following code:
public class Foo
{
public int Bar { get; set; }
}
public class SomeOtherFoo
{
public int Bar { get; set; }
}
Should I be able to say:
Foo foo = new SomeOtherFoo();
That won't work in C# either. When you have two different types that have the same body/implementation, they are still different types. Two classes with the same properties are still different classes. Two different delegates with the same signature are still different delegates.
The Sort method has already defined the delegate type, and you need to match it. This is very much like it defining a class that it needs to accept as a parameter; you can't just pass in another type with the same properties and methods.
This is what it means for a language to be statically typed. An alternate type system would be to use "Duck Typing" in which the language doesn't apply the constraint that a variable be of a specific type, but rather that it has a specific set of members. In other words, "If it walks like a duck, and quacks like a duck, pretend it's a duck." That is opposed to the style of typing that says, "It must be a duck, period, even if it knows how to walk and quack."
Use of delegates follows the same rules as calling methods - you can only refer to a method via a delegate if you are allowed to call that method explicitly, which means you cannot reference a non-static method from a static method, even if you don't actually call it. Is there a way around that?
Here is some code used in performing the Bowling Kata, with my ideal lines of code shown in comments. I was forced to go through a static call (and anonymous static method declarations) to make the Frame Class code declarative to my liking:
public int FrameScore()
{
return scorer[FrameType()](this);
// I would like it to be
// return this.scorer[FrameType()]();
}
static Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>> scorer =
new Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>>()
{
{LinkedFrame.FrameTypeEnum.Strike, frame => frame.StrikeScore()},
{LinkedFrame.FrameTypeEnum.Spare, frame => frame.SpareScore()},
{LinkedFrame.FrameTypeEnum.Regular, frame => frame.RegularScore()}
// I would like an element to be
// {LinkedFrame.FrameTypeEnum.Strike, StrikeScore}
};
private int RegularScore()
{
return this.Sum;
}
private int SpareScore()
{
...
}
private int StrikeScore()
{
...
}
So in some contexts it would make sense to reason about non-static methods in a static context. Is there a way to do this?
Maybe open instance delegates will help?
According to MSDN: Delegate Class:
When a delegate represents an instance method closed over its first argument (the most common case), the delegate stores a reference to the method's entry point and a reference to an object, called the target, which is of a type assignable to the type that defined the method. When a delegate represents an open instance method, it stores a reference to the method's entry point. The delegate signature must include the hidden this parameter in its formal parameter list; in this case, the delegate does not have a reference to a target object, and a target object must be supplied when the delegate is invoked.
What it comes down to, is that you can sneakily convert an instance method to a static method with an explicit this parameter. You can see how it's done here: Simon Cooper: Introduction to open instance delegates
An instance method always requires an instance to be invoked with.
If you want to invoke an instance method through a delegate, you have two options:
The delegate captures the instance in some way.
You need to pass the instance to the delegate.
You seem to want to have a delegate that does not capture an instance and does not require an instance to be passed. That's not possible in C#.
Im having a little trouble understanding delegates.
I have a delegate that i will invoke when a y character is entered:
public delegate void respondToY(string msgToSend);
private respondToY yHandler;
i have a subscribe method in order that calling code can ask to be notified when the delegate is invoked:
public void Subscribe(respondToY methodName)
{
yHandler += methodName;
}
As far as i can see, to register with this delegate, i need to provide something of the type respondToY. Yet when calling the subscribe method, i can supply either a new instance of the delegate or simply the name of the method. Does this mean that any method matching the delegate signature can be used and will automatically be converted to the correct delegate type?
** Edit **
So on this assumption it would also be valid to supply only a method name to things like click event handlers for buttons (provided the method took the sender, and the relevant event object), it would be converted to the required delegate?
This is a method group conversion. It converts a method group (basically the name of a method or overloaded methods) to an instance of a delegate type with a compatible signature.
Yes, any compatible method can be used. Note that you can provide a target too - for example:
string text = "Hello there";
Func<int, int, string> func = text.Substring;
Console.WriteLine(func(2, 3)); // Prints "llo", which is text.Substring(2, 3)
There must be a specific delegate type involve though. You can't just use:
Delegate x = methodName;
... the compiler doesn't know the kind of delegate to create.
For more information, see section 6.6 of the C# 4 language specification.
Note that a method group conversion always creates a new instance of the delegate in question - it isn't cached (and can't be without violating the specification.)
as far as i know ... yes, the delegate type just makes sure that the signatures match