167 Replies
I believe we already did :p
I didn't get it :I
Imagine you have a bunch of toys, and you like to play with them in different ways. Sometimes you want to race your toy cars, other times you want to build a tower with blocks. Now, imagine you have a special box called "Delegate Box". This box doesn't play with the toys by itself, but it holds instructions on how you want to play. So, you can tell the box: "Today, I want to race the cars," and it remembers that. Tomorrow, you can tell it: "Now I want to build a tower!" The box doesn't care what the instructions areβit just remembers them and gives them to the toys. In C#, a delegate is like that box. It holds instructions (a reference to a method) for doing something, and when you need it, you tell the delegate to do whatever it has been asked to do, without caring how it works inside. Does that make sense? The delegate is like a magic helper that holds instructions on how to do things!Actually a pretty good ELI5
Ok so delegates holds instructions for how to do something? (a method)
a
delegate
is a type (like class, or struct, or enum)
instead of holding objects or values, a delegate hold a method
a delegates parameters declare what parameters/return value a method must have to "fit" the delegate
this one for example requires a method to return a decimal
and take two int
s in to fitOk, so we pass a method to
PerformCalculation
and not int x, int y
?
But the method we pass must match the parameters of the delegate?yes
What's the benefit of passing a method rather than just passing the values/types to a normal method instead?
Which of these would match the above delegate?
Because we can pass the method reference around (as a delegate) to let some other code decide when to use it
the second one
remove
(except the typo inte) since it returns a decimal and takes 2 integers k and xcorrect. the names dont matter
only the types matter
Couldn't we just call the
remove
directly instead of having to do a delegate?
especially since it's public and staticwe could, but where delegates become useful is when we need to separate the decision of what method to call and when to actually call it
Hmm, i'm 100% clear on what it is now, i'm just a little unclear what that last part means
If i were writing some code, for eg a calculator, i would just call the methods i need directly such as Add, Sub, Mult etc instead of passing the method of Add, Sub, Mult to the delegate which then in turn performs the calculations
But i'm probably missing the point of delegates
Yeah
let me find a good example
:catthinking:
okay
You are writing a console app
one thing you do a lot in console apps is ask the user for input
so you, as a clever developer, decide to write a method to help you make this easier
like
string username = AskUser("What is your username?");
with me so far?Yeah
okay. We use this method for several things. Like, asking for a username, their date of birth, their first and last names... etc
all is good
Right
then someone types "CHEESECAKE" as their birthdate
and your program crashes
okay, thats a problem. We need to validate the input
One way to do this would be to write something like...
but alas, if the user keeps entering invalid values, we have problems
okay, so we use a loop to re-ask until the user enters a valid value!
but we need to do this EVERYWHERE we ask for user input....
and what is a "valid value" changes depending on what we asked
like, everyone knows lastnames can only end in
sson
birthdates are purely numeric, except for the dashes.
ages are numeric with no other signs allowed
etc
so now our code is super messyYeah for sure, having to take into account every single possible problem would create a lot of code
so now our code looks like this
we can see that there is a pattern here, right?
we store the given value, then we validate it and ask again with a loop
and we do this for every input, with the difference beeing what we ask for, the validation method and what the error message is if its invalid
so what if we could change our
AskUser
method to take these in?
something like...
wouldnt that be nice?
like, if we could do that, the code above would turn into...
damn, thats so much nicer!
Are you still with me?I think so? I'm not familiar with tying string as my parameters tho
wdym?
In the parameters for AskUser you are typing strings
its just a string as a parameter. same thing as
Add(5,10);
except there its intsIn that case 5 and 10 are arguments
You are using the strings as parameters
so?
I've never done that before, didn't even know that was allowed
there is no difference, except int instead of string
of course its allowed
Parameters are a type followed by a name
I don't see that in ur example
I see a text of string, a name and then a text of string again
thats only in declarations of methods
not in usages
when you USE a method, you just give a value. Either as a literal (typed as is then and there) or a variable
Ok, so you are passing 2 strings and a aValidateUsername method?
yeah, something like that
:/
our old method looked like this:
when it just had one parameter
the new one looks like this:
Γk so how does the AskUser method look like declared?
but now I ask you...
what can we type there?
what type exists in C# that can accept a method of a known signature?
It's a delegate, but i got lost in the last part of the example.
ok lets rewind and fix that confusion first then
can you tell me exactly where I lost you?
Delegates are pointers to a function, it's just a way of passing the location of a function (and its signature) around.
Let's say you have a list of integers and a function that squares integers and you want to end up with a list of squared integers.
Then going further you could expand out to a generic use case:
Which you could then call do to all sorts of things!
And so on so forth.
This is (basically) what LINQ's Select method is doing:
Not sure how its helpful to drop a full page of code involving lambdas and generics to someone not understanding delegates my guy
Gives some code to try and then watch what it gets up to, hard to explain the concept without involving the type signatures of what's going on.
Is !ValidateLastname a CBL method?
no, its a method you would write yourself
we can already tell it returns a bool (since its used as a condition for a while), and that it takes in a string
for example
I'm with you to this part. Everytime we ask the user for input we have to validate what they wrote, age, name, etc.
yep
the thing is, we dont want to write a new method for each step
like, I dont want to write a
AskUserForName
method, and a AskUserForLastname
method, and a AskUserForBirthdate
methodWe have to? The error message and the condition changes for every input the user puts in?
I want to write ONE method for asking for input, and using parameters to change what it does
in the calculator example, you dont write a
AddFivePlusSeven()
method
you write a single Add(int x, int y)
methodOk, can a delegate handle all of these possible inputs and error messages?
wait
what?
what does the error message have to do with the delegates?
Idk? You tell me
You are trying to tell me that you can handle every error message, validate the string the user inputs and output the correct message with just one method
yeah, but only the validation has anything to do with delegates
the prompt and the error message are just completely normal method parameters
for example, here is AskUser without custom validation:
Ok. In that case the parameter for the delegate would just be a string and the return would be void.
π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£ π€£
this makes no sense now
what makes no sense?
we haven't gotten to delegates yet
:p
\o/
Idk the example ig
You lost me when you tried introducing two strings as messages and a validate method
ignore the validation method for now
I dont understand how strings are confusing you thou
Not sure how to respond to that
If i don't get it i don't get it :/
a string is just another datatype
If i wanted to ask the user for user input
there is nothing different about them as opposed to say ints, or decimals, or doubles
continue this line of thought, please
Nah idk anymore
i'm 100% fully lost now
I know what a delegate is now but the usage for it make absolutely zero sence
I cant even get to the delegate example because you got stuck on string parameters :/
Why would i ever want to pass something to a delegate when i can just call the method i want directly? It makes nooooooooo sense. It's just an unnecessary step
it really isnt
but look
you said yourself that this was perfectly fine and not confusing
mm'
so why did it become confusing when I added a second string?
@Clint why are you dming me?
Like i have this channel open for a reason :/
Just letting you know that I'm available if you want options and alternative ways of going through this, I think it's great you're looking to learn this, but appreciate that a busy chat window isn't always the best forum for it π
No worries if not though, no problem.
Its absolutely fine to drop options and alternatives in the thread. Unsolicited DMs are discouraged.
Ah I wasn't aware, apologies.
No worries
But my offer still stands, we will have you understanding how delegates work cos they're an extremely useful tool!
Pobiega is right, multitude of uses
And they show up all over the place in the core library
I think we are pretty close to introducing them, if we can just get over the string confusion π
Ok so you are creating a method
AskUser
which has the parameters and return type string Askuser(string username, method ValidateUsername, string error message)
?What if take a step back? Merineth what problem is you're trying to solve? Perhaps we can tackle from first principles and slot the delegates in gradually?
yeah pretty much!
Ok
the thing is that what the validate method does changes depending on what we ask for
right?
we validate usernames differently from lastnames, or birthdates
Yes
but everything else about the "asking user for input" remains exactly the same
and we know that delegates are how we pass methods around... so we reach this point:
What do you think we should replace the two
?
with?
remember, delegates are types, but also strictly typed - they declare what method signatures are valid for the delegate
hint: if(validator(input))
tells you a lot about the delegateAnd if it helps, think of:
Like the way you'd write a method signature, just with an extra keyword at the start, and NO implementation body.
yep
string and string?
is
if("hello")
valid?
what does an if()
expect to be passed in?
This is what i'd do for your example.
yeah, makes sense. thats how you solve this problem without delegates
but look how similar those methods are
they are in fact almost identical
yes, in terms of parameters and return value
exactly
so, can we maybe return to the delegate example? we really are SO CLOSE
Haha yeah we are probably close for you to understand it :/
but i don't get it
I mean, it feels like you are not really giving me/it a chance here
I fail to see how you can take a parameter, a return value and have them do two different things without making two different methods for them
What more can i say, i'm trying
Take the types of the return value and the arguments, what do you think the delegate signature looks like for that?
what must the delegate declaration look like for that method to be valid for the delegate?
Like that ig?
so close
Why string as return value?
what return value does the method have?
my example or yours?
yours
it returns v, a string
Oh okay, I see the confusion here, your ask methods are returning
string
but we're getting tripped up on the validation partOh yeah, skip that. We're back to using separate validation methods, not your "all in one" methods
for example
this is my suggested lastname validator that is a little biased regarding what constitutes a valid lastname
EndsWith is a CBL method which returens a bool?
That's more like what we're aiming for, yes? Where
?
is the delegate to perform the validation check.yes (but its called BCL :D)
Ok
In that case it looks like this
inside the if for askusername i'd include it there
why are we back to your example?
I thought we never left?
As said, thats how we do things without delegates
but you are trying to learn delegates
Ok, so where are we then?
What code are we basing it of
ok
I don't get the last delegate part, everything else is fine
well, a validation method here takes in a string (the suggested value) and returns a bool (if it was valid or not)
the delegate declares what signature a method must have to be a validator
any method that takes in a string and returns a bool can be used as a validator
Ok, but you are still missing
ValidateBirthdate
and ValidateLastname
?username and birthdate, yes
they would have the exact same signature, but different bodies
here are some suggestions of potential bodies
notice how they all have the same return value, and the same input parameters, but different names, different bodies
Yes.
so with a delegate, we can separate out the part that was actually different, and re-use the parts that were the same
asking the user for input, taking in the value, checking if it was valid, all that was the same. The only part that actually changed between our three calls was "what constitutes a valid value for this variable?"
So we are here?
yes
We can clean this up even further, but that would involve using generics and lambda methods, which you might not be comfortable with yet π
So instead of having 3 different Askuser functions for username, birthdate and lastname we create one generic askuser function and pass the criteria it needs as a method by utilizing a delegate?
yes!
exactly so
and this is good, because if you later need to change something about how you ask users for input, you can change that in ONE place - instead of in each method
Ok i do see the benefit of delegates, it's just so hard for me to utilize without practice that i'd end up doing the 3 askuser functions because it'd go faster for me
I mean, thats to be expected, you have known methods for a while now but understood delegates maybe a few minutes ago
Learning of something != naturalizing it
You mentionder generics and lambda methods?
Got until monday to learn everything lol, so i gotta try at least
yeah. Do you perhaps remember us speaking of
Action<T>
and Func<TResult, T>
?Yes
we called them "generic delegates"
and
=>
because thats what they are
Yea, generic because of the
T
well, actually because of the
<>
iirc it's generic becuase we don't know the input type?
yeah, its a placeholder
so here is the same ask method with a generic delegate instead of your own
Right, sorry
<>
. The T is just the name of the parameterexactly
boom, same method, only thing changed was I replaced
ValidatorDelegate
with Func<string, bool>
So we end up like this?
almost. you can safely throw the delegate declaration at the bottom
we dont need it anymore
there you go
The
Func<>
does that for us?yep
look at the types it takes in
string and bool
the last type is the return value
so
Func<T, TResult>
returns a TResult
and takes a T
in,
is return value and right side of ,
is input parameter?yeah, opposite
Ok so the right side of , is return value and left side of , is input parameter?
look here at what Rider is showing me
What's the difference between
Func<T>
and Action<T>
I think it was called action?it is!
Action
has a void return typeAh
So this would be Action?
yep!
Action<string>
would be matched by the same methodsMakes sense
what abt lambda?
sooooooo
this method
is very short
what if we could just.... skip declaring it and giving it a name? we only use it in one place anyways
what if I told you we can do just that
BOOM
this is called "an anonymous method"
Right i remember that
a method that isn't declared
just instantly used
sort of
it is actually declared, this isnt a usage
So essentially, delegates, func, action and lambda are things in C# to make code faster to write and easier to read?
yeah
remember, all this compiles down to CPU instructions at the end anyways
and thats true for all programming languages
so everything that isnt a raw CPU instruction is just a convenience for the developer π
Does it become easier for the CPU to handle if we use delegates, or is it purely for the dev?
purely for the devs
Makes sense
purely for the dev convience (except me)
you have a point. Look at the Go programming language as an example
But yea i got a decent basic understanding of delegates now
its intentionally kept simple and low amount of features
Not sure how i'm gonna practice it tho
because introducing many alternative ways to do the same thing => different styles and confusion
there is a certain value to that too
thats fair. Try experimenting with this validation code we have here
for example, what would happen if I suddenly wanted to ask the user for an
int
directly, instead of a string?We were only given one exercise which includes lambda ...
and it's kind of complex
here is a screenshot of my
ConsoleHelper
methods I use when I write console apps, as inspiration. Plenty of lambdas, generics and delegates hereAm i high?
Or are there no lambda expression in this code
Can the Action<T> class be replaced with a user-
defined delegate type with the same functionality?
Shouldn't the Action<T>
have two parameters?
π ok this is wayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy to complicated
thanks course responsible
Anyhow i'll continue with my studies (not delegates) thanks for tthe help!