βœ… Can someone explain Delegates to me like i'm 5?

:(
167 Replies
Pobiega
Pobiegaβ€’3mo ago
I believe we already did :p
Merineth πŸ‡ΈπŸ‡ͺ
I didn't get it :I
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Ok so delegates holds instructions for how to do something? (a method)
Pobiega
Pobiegaβ€’3mo ago
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
public delegate decimal PerformCalculation(int x, int y);
public delegate decimal PerformCalculation(int x, int y);
this one for example requires a method to return a decimal and take two ints in to fit
Merineth πŸ‡ΈπŸ‡ͺ
Ok, 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?
Pobiega
Pobiegaβ€’3mo ago
yes
Merineth πŸ‡ΈπŸ‡ͺ
What's the benefit of passing a method rather than just passing the values/types to a normal method instead?
Pobiega
Pobiegaβ€’3mo ago
public static int Add(int a, int b) { ... }
public static decimal Remove(int k, int x) { ... }
public static int Add(int a, int b) { ... }
public static decimal Remove(int k, int x) { ... }
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
Merineth πŸ‡ΈπŸ‡ͺ
the second one remove (except the typo inte) since it returns a decimal and takes 2 integers k and x
Pobiega
Pobiegaβ€’3mo ago
correct. the names dont matter only the types matter
Merineth πŸ‡ΈπŸ‡ͺ
Couldn't we just call the removedirectly instead of having to do a delegate? especially since it's public and static
Pobiega
Pobiegaβ€’3mo ago
we 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
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
Yeah let me find a good example
Merineth πŸ‡ΈπŸ‡ͺ
:catthinking:
Pobiega
Pobiegaβ€’3mo ago
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?
Merineth πŸ‡ΈπŸ‡ͺ
Yeah
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Right
Pobiega
Pobiegaβ€’3mo ago
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...
string birthdate = AskUser("Enter your birthdate: ");
if(StringIsValidBirthdate(birthdate))
{
Console.WriteLine("You entered a valid birthdate.");
}
else
{
Console.WriteLine("You entered an invalid birthdate.");
birthDate = AskUser("Enter your birthdate again: ");
}
string birthdate = AskUser("Enter your birthdate: ");
if(StringIsValidBirthdate(birthdate))
{
Console.WriteLine("You entered a valid birthdate.");
}
else
{
Console.WriteLine("You entered an invalid birthdate.");
birthDate = AskUser("Enter your birthdate again: ");
}
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 messy
Merineth πŸ‡ΈπŸ‡ͺ
Yeah for sure, having to take into account every single possible problem would create a lot of code
Pobiega
Pobiegaβ€’3mo ago
so now our code looks like this
string birthdate = AskUser("Enter your birthdate: ");
while (!ValidBirthdate(birthdate))
{
birthdate = AskUser("Invalid birthdate. Please enter a valid birthdate: ");
}

string lastname = AskUser("Enter your lastname: ");
while (!ValidLastname(lastname))
{
lastname = AskUser("Invalid lastname. Please enter a valid lastname: ");
}
string birthdate = AskUser("Enter your birthdate: ");
while (!ValidBirthdate(birthdate))
{
birthdate = AskUser("Invalid birthdate. Please enter a valid birthdate: ");
}

string lastname = AskUser("Enter your lastname: ");
while (!ValidLastname(lastname))
{
lastname = AskUser("Invalid lastname. Please enter a valid lastname: ");
}
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...
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
wouldnt that be nice? like, if we could do that, the code above would turn into...
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");
damn, thats so much nicer! Are you still with me?
Merineth πŸ‡ΈπŸ‡ͺ
I think so? I'm not familiar with tying string as my parameters tho
Pobiega
Pobiegaβ€’3mo ago
wdym?
Merineth πŸ‡ΈπŸ‡ͺ
In the parameters for AskUser you are typing strings
Pobiega
Pobiegaβ€’3mo ago
its just a string as a parameter. same thing as Add(5,10); except there its ints
Merineth πŸ‡ΈπŸ‡ͺ
In that case 5 and 10 are arguments You are using the strings as parameters
Pobiega
Pobiegaβ€’3mo ago
so?
Merineth πŸ‡ΈπŸ‡ͺ
I've never done that before, didn't even know that was allowed
Pobiega
Pobiegaβ€’3mo ago
there is no difference, except int instead of string of course its allowed
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Ok, so you are passing 2 strings and a aValidateUsername method?
Pobiega
Pobiegaβ€’3mo ago
yeah, something like that
Merineth πŸ‡ΈπŸ‡ͺ
:/
Pobiega
Pobiegaβ€’3mo ago
our old method looked like this:
string AskUser(string prompt)
{
Console.WriteLine(prompt);
return Console.ReadLine();
}
string AskUser(string prompt)
{
Console.WriteLine(prompt);
return Console.ReadLine();
}
when it just had one parameter the new one looks like this:
string AskUser(string prompt, what_do_we_type_here validator, string errorMessage)
...
string AskUser(string prompt, what_do_we_type_here validator, string errorMessage)
...
Merineth πŸ‡ΈπŸ‡ͺ
Γ“k so how does the AskUser method look like declared?
Pobiega
Pobiegaβ€’3mo ago
but now I ask you... what can we type there? what type exists in C# that can accept a method of a known signature?
Merineth πŸ‡ΈπŸ‡ͺ
It's a delegate, but i got lost in the last part of the example.
Pobiega
Pobiegaβ€’3mo ago
ok lets rewind and fix that confusion first then can you tell me exactly where I lost you?
Clint
Clintβ€’3mo ago
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.
int Square(int num) {
return num ^ 2;
}

List<int> SquareIntsTheOldWay(List<int> ints) {
var result = new List<int>();

foreach(var num in ints) {
result.Add(Square(num));
}

return result;
}

List<int> DoSomethingToInts(List<int> nums, Func<int, int> something) {
var result = new List<int>();
foreach(var num in nums) {
result.Add(something(num));
}
}
int Square(int num) {
return num ^ 2;
}

List<int> SquareIntsTheOldWay(List<int> ints) {
var result = new List<int>();

foreach(var num in ints) {
result.Add(Square(num));
}

return result;
}

List<int> DoSomethingToInts(List<int> nums, Func<int, int> something) {
var result = new List<int>();
foreach(var num in nums) {
result.Add(something(num));
}
}
Then going further you could expand out to a generic use case:
IEnumerable<T> DoSomethingToInts(IEnumerable<int> nums, Func<int, T> something) {
foreach(var num in nums) {
yield return something(num);
}
}
IEnumerable<T> DoSomethingToInts(IEnumerable<int> nums, Func<int, T> something) {
foreach(var num in nums) {
yield return something(num);
}
}
Which you could then call do to all sorts of things!
var Squared = DoSomethingToInts(myInts, (i) => i ^ 2);

var toString = DoSomethingToInts(myInts, (i) => i.ToString());
var Squared = DoSomethingToInts(myInts, (i) => i ^ 2);

var toString = DoSomethingToInts(myInts, (i) => i.ToString());
And so on so forth. This is (basically) what LINQ's Select method is doing:
var squared = myInts.Select((i) => i ^ 2);
var squared = myInts.Select((i) => i ^ 2);
Pobiega
Pobiegaβ€’3mo ago
Not sure how its helpful to drop a full page of code involving lambdas and generics to someone not understanding delegates my guy
Clint
Clintβ€’3mo ago
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.
Merineth πŸ‡ΈπŸ‡ͺ
Is !ValidateLastname a CBL method?
Pobiega
Pobiegaβ€’3mo ago
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
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
for example
Merineth πŸ‡ΈπŸ‡ͺ
I'm with you to this part. Everytime we ask the user for input we have to validate what they wrote, age, name, etc.
Pobiega
Pobiegaβ€’3mo ago
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 method
Merineth πŸ‡ΈπŸ‡ͺ
We have to? The error message and the condition changes for every input the user puts in?
Pobiega
Pobiegaβ€’3mo ago
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) method
Merineth πŸ‡ΈπŸ‡ͺ
Ok, can a delegate handle all of these possible inputs and error messages?
Pobiega
Pobiegaβ€’3mo ago
wait what? what does the error message have to do with the delegates?
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
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:
string AskUser(string prompt, string errorMessage)
{
while (true)
{
Console.Write(prompt);
var input = Console.ReadLine();


if (input == null)
{
Console.WriteLine(errorMessage);
}
else
{
return input;
}
}
}
string AskUser(string prompt, string errorMessage)
{
while (true)
{
Console.Write(prompt);
var input = Console.ReadLine();


if (input == null)
{
Console.WriteLine(errorMessage);
}
else
{
return input;
}
}
}
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
what makes no sense? we haven't gotten to delegates yet :p
Merineth πŸ‡ΈπŸ‡ͺ
\o/ Idk the example ig You lost me when you tried introducing two strings as messages and a validate method
Pobiega
Pobiegaβ€’3mo ago
ignore the validation method for now I dont understand how strings are confusing you thou
Merineth πŸ‡ΈπŸ‡ͺ
Not sure how to respond to that If i don't get it i don't get it :/
Pobiega
Pobiegaβ€’3mo ago
a string is just another datatype
Merineth πŸ‡ΈπŸ‡ͺ
If i wanted to ask the user for user input
Pobiega
Pobiegaβ€’3mo ago
there is nothing different about them as opposed to say ints, or decimals, or doubles continue this line of thought, please
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
I cant even get to the delegate example because you got stuck on string parameters :/
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
it really isnt but look you said yourself that this was perfectly fine and not confusing
string birthdate = AskUser("Enter your birthdate: ");
string birthdate = AskUser("Enter your birthdate: ");
Merineth πŸ‡ΈπŸ‡ͺ
mm'
Pobiega
Pobiegaβ€’3mo ago
so why did it become confusing when I added a second string?
string birthdate = AskUser("Enter your birthdate: ", "Invalid birthdate, try again.");
string birthdate = AskUser("Enter your birthdate: ", "Invalid birthdate, try again.");
Merineth πŸ‡ΈπŸ‡ͺ
@Clint why are you dming me? Like i have this channel open for a reason :/
Clint
Clintβ€’3mo ago
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.
Pobiega
Pobiegaβ€’3mo ago
Its absolutely fine to drop options and alternatives in the thread. Unsolicited DMs are discouraged.
Clint
Clintβ€’3mo ago
Ah I wasn't aware, apologies.
Pobiega
Pobiegaβ€’3mo ago
No worries
Clint
Clintβ€’3mo ago
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
Pobiega
Pobiegaβ€’3mo ago
I think we are pretty close to introducing them, if we can just get over the string confusion πŸ™‚
Merineth πŸ‡ΈπŸ‡ͺ
Ok so you are creating a method AskUser which has the parameters and return type string Askuser(string username, method ValidateUsername, string error message)?
Clint
Clintβ€’3mo ago
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?
Pobiega
Pobiegaβ€’3mo ago
yeah pretty much!
Merineth πŸ‡ΈπŸ‡ͺ
Ok
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Yes
Pobiega
Pobiegaβ€’3mo ago
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:
delegate ? ValidatorDelegate(? input);

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
delegate ? ValidatorDelegate(? input);

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
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 delegate
Clint
Clintβ€’3mo ago
And if it helps, think of:
delegate ? ValidatorDelegate(? input);
delegate ? ValidatorDelegate(? input);
Like the way you'd write a method signature, just with an extra keyword at the start, and NO implementation body.
Pobiega
Pobiegaβ€’3mo ago
yep
Merineth πŸ‡ΈπŸ‡ͺ
string and string?
Pobiega
Pobiegaβ€’3mo ago
is if("hello") valid? what does an if() expect to be passed in?
Merineth πŸ‡ΈπŸ‡ͺ
internal class Program
{
static void Main(string[] args)
{
string username = AskUsername("What's your username");
string age = AskAge("What's your age?");
}

private static string AskAge(string v)
{
if(/*it isn't an integer between 18 and 100*/)
{
Console.WriteLine("Wrong input");
AskAge(v);
}
}

private static string AskUsername(string v)
{
if (/*doesn't end it sson*/)
{
Console.WriteLine("Wrong input");
AskUsername(v);
}
else
{
return v;
}
}
}
internal class Program
{
static void Main(string[] args)
{
string username = AskUsername("What's your username");
string age = AskAge("What's your age?");
}

private static string AskAge(string v)
{
if(/*it isn't an integer between 18 and 100*/)
{
Console.WriteLine("Wrong input");
AskAge(v);
}
}

private static string AskUsername(string v)
{
if (/*doesn't end it sson*/)
{
Console.WriteLine("Wrong input");
AskUsername(v);
}
else
{
return v;
}
}
}
This is what i'd do for your example.
Pobiega
Pobiegaβ€’3mo ago
yeah, makes sense. thats how you solve this problem without delegates but look how similar those methods are they are in fact almost identical
Merineth πŸ‡ΈπŸ‡ͺ
yes, in terms of parameters and return value
Pobiega
Pobiegaβ€’3mo ago
exactly so, can we maybe return to the delegate example? we really are SO CLOSE
Merineth πŸ‡ΈπŸ‡ͺ
Haha yeah we are probably close for you to understand it :/ but i don't get it
Pobiega
Pobiegaβ€’3mo ago
I mean, it feels like you are not really giving me/it a chance here
Merineth πŸ‡ΈπŸ‡ͺ
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
Clint
Clintβ€’3mo ago
public bool ValidateLastName(string value) {
// return some validation pass / fail result
}
public bool ValidateLastName(string value) {
// return some validation pass / fail result
}
Take the types of the return value and the arguments, what do you think the delegate signature looks like for that?
Pobiega
Pobiegaβ€’3mo ago
what must the delegate declaration look like for that method to be valid for the delegate?
Merineth πŸ‡ΈπŸ‡ͺ
public delegate string AskUser(string input);
public delegate string AskUser(string input);
Like that ig?
Clint
Clintβ€’3mo ago
so close
Pobiega
Pobiegaβ€’3mo ago
Why string as return value? what return value does the method have?
Merineth πŸ‡ΈπŸ‡ͺ
my example or yours?
Pobiega
Pobiegaβ€’3mo ago
yours
Merineth πŸ‡ΈπŸ‡ͺ
it returns v, a string
Clint
Clintβ€’3mo ago
Oh okay, I see the confusion here, your ask methods are returning string but we're getting tripped up on the validation part
Pobiega
Pobiegaβ€’3mo ago
Oh yeah, skip that. We're back to using separate validation methods, not your "all in one" methods
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
for example this is my suggested lastname validator that is a little biased regarding what constitutes a valid lastname
Merineth πŸ‡ΈπŸ‡ͺ
EndsWith is a CBL method which returens a bool?
Clint
Clintβ€’3mo ago
public string AskUser(string message, ? validator, string failureMessage) {
var value = Console.ReadLine(message);
if (!validator(value)) {
Console.WriteLine(failureMessage);
}

// code to go around while we don't have a valid value not included
}
public string AskUser(string message, ? validator, string failureMessage) {
var value = Console.ReadLine(message);
if (!validator(value)) {
Console.WriteLine(failureMessage);
}

// code to go around while we don't have a valid value not included
}
That's more like what we're aiming for, yes? Where ? is the delegate to perform the validation check.
Pobiega
Pobiegaβ€’3mo ago
yes (but its called BCL :D)
Merineth πŸ‡ΈπŸ‡ͺ
Ok
internal class Program
{
static void Main(string[] args)
{
string username = AskUsername("What's your username");
string age = AskAge("What's your age?");
}

private static string AskAge(string v)
{
if(/*it isn't an integer between 18 and 100*/)
{
Console.WriteLine("Wrong input");
AskAge(v);
}
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

private static string AskUsername(string v)
{
if (/*doesn't end it sson*/)
{
Console.WriteLine("Wrong input");
AskUsername(v);
}
else
{
return v;
}
}
internal class Program
{
static void Main(string[] args)
{
string username = AskUsername("What's your username");
string age = AskAge("What's your age?");
}

private static string AskAge(string v)
{
if(/*it isn't an integer between 18 and 100*/)
{
Console.WriteLine("Wrong input");
AskAge(v);
}
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

private static string AskUsername(string v)
{
if (/*doesn't end it sson*/)
{
Console.WriteLine("Wrong input");
AskUsername(v);
}
else
{
return v;
}
}
In that case it looks like this inside the if for askusername i'd include it there
Pobiega
Pobiegaβ€’3mo ago
why are we back to your example?
Merineth πŸ‡ΈπŸ‡ͺ
I thought we never left?
Pobiega
Pobiegaβ€’3mo ago
As said, thats how we do things without delegates but you are trying to learn delegates
Merineth πŸ‡ΈπŸ‡ͺ
Ok, so where are we then? What code are we basing it of
Pobiega
Pobiegaβ€’3mo ago
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}

delegate bool ValidatorDelegate(string input);
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}

delegate bool ValidatorDelegate(string input);
Merineth πŸ‡ΈπŸ‡ͺ
ok I don't get the last delegate part, everything else is fine
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Ok, but you are still missing ValidateBirthdate and ValidateLastname?
Pobiega
Pobiegaβ€’3mo ago
username and birthdate, yes they would have the exact same signature, but different bodies
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
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
Merineth πŸ‡ΈπŸ‡ͺ
Yes.
Pobiega
Pobiegaβ€’3mo ago
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?"
Merineth πŸ‡ΈπŸ‡ͺ
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}

delegate bool ValidatorDelegate(string input);
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, ValidatorDelegate validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}

delegate bool ValidatorDelegate(string input);
So we are here?
Pobiega
Pobiegaβ€’3mo ago
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 πŸ™‚
Merineth πŸ‡ΈπŸ‡ͺ
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?
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
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
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
You mentionder generics and lambda methods? Got until monday to learn everything lol, so i gotta try at least
Pobiega
Pobiegaβ€’3mo ago
yeah. Do you perhaps remember us speaking of Action<T> and Func<TResult, T>?
Merineth πŸ‡ΈπŸ‡ͺ
Yes
Pobiega
Pobiegaβ€’3mo ago
we called them "generic delegates"
Merineth πŸ‡ΈπŸ‡ͺ
and =>
Pobiega
Pobiegaβ€’3mo ago
because thats what they are
Merineth πŸ‡ΈπŸ‡ͺ
Yea, generic because of the T
Pobiega
Pobiegaβ€’3mo ago
well, actually because of the <>
Merineth πŸ‡ΈπŸ‡ͺ
iirc it's generic becuase we don't know the input type?
Pobiega
Pobiegaβ€’3mo ago
yeah, its a placeholder so here is the same ask method with a generic delegate instead of your own
string AskUser(string prompt, Func<string, bool> validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
string AskUser(string prompt, Func<string, bool> validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
Merineth πŸ‡ΈπŸ‡ͺ
Right, sorry <> . The T is just the name of the parameter
Pobiega
Pobiegaβ€’3mo ago
exactly boom, same method, only thing changed was I replaced ValidatorDelegate with Func<string, bool>
Merineth πŸ‡ΈπŸ‡ͺ
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, Func<string, bool> validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
string username = AskUser("Enter username:", ValidateUsername, "Invalid username, try again");
string birthdate = AskUser("Enter your birthdate: ", ValidateBirthdate, "Invalid birthdate, try again");
string lastname = AskUser("Enter your lastname: ", ValidateLastname, "Invalid lastname, try again");

bool ValidateBirthdate(string birthdate)
{
return DateTime.TryParse(birthdate, out _);
}

bool ValidateUsername(string username)
{
return username.Length > 3;
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}

string AskUser(string prompt, Func<string, bool> validator, string errorMessage)
{
while (true)
{
Console.Write(prompt);
string input = Console.ReadLine();

if (validator(input))
{
return input;
}

Console.WriteLine(errorMessage);
}
}
So we end up like this?
Pobiega
Pobiegaβ€’3mo ago
almost. you can safely throw the delegate declaration at the bottom we dont need it anymore there you go
Merineth πŸ‡ΈπŸ‡ͺ
The Func<> does that for us?
Pobiega
Pobiegaβ€’3mo ago
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
Merineth πŸ‡ΈπŸ‡ͺ
Ok so the left side of , is return value and right side of , is input parameter? No opposite?
Pobiega
Pobiegaβ€’3mo ago
yeah, opposite
Merineth πŸ‡ΈπŸ‡ͺ
Ok so the right side of , is return value and left side of , is input parameter?
Pobiega
Pobiegaβ€’3mo ago
No description
Pobiega
Pobiegaβ€’3mo ago
look here at what Rider is showing me
Merineth πŸ‡ΈπŸ‡ͺ
What's the difference between Func<T> and Action<T> I think it was called action?
Pobiega
Pobiegaβ€’3mo ago
it is! Action has a void return type
Merineth πŸ‡ΈπŸ‡ͺ
Ah
public delegate void AskUser(string input)
public delegate void AskUser(string input)
So this would be Action?
Pobiega
Pobiegaβ€’3mo ago
yep! Action<string> would be matched by the same methods
Merineth πŸ‡ΈπŸ‡ͺ
Makes sense what abt lambda?
Pobiega
Pobiegaβ€’3mo ago
sooooooo
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
bool ValidateLastname(string name)
{
return name.EndsWith("sson");
}
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
string lastname = AskUser("Enter your lastname: ", name => name.EndsWith("sson"), "Invalid lastname, try again");
string lastname = AskUser("Enter your lastname: ", name => name.EndsWith("sson"), "Invalid lastname, try again");
BOOM this is called "an anonymous method"
Merineth πŸ‡ΈπŸ‡ͺ
Right i remember that a method that isn't declared just instantly used
Pobiega
Pobiegaβ€’3mo ago
sort of it is actually declared, this isnt a usage
Merineth πŸ‡ΈπŸ‡ͺ
So essentially, delegates, func, action and lambda are things in C# to make code faster to write and easier to read?
Pobiega
Pobiegaβ€’3mo ago
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 πŸ˜„
Merineth πŸ‡ΈπŸ‡ͺ
Does it become easier for the CPU to handle if we use delegates, or is it purely for the dev?
Pobiega
Pobiegaβ€’3mo ago
purely for the devs
Merineth πŸ‡ΈπŸ‡ͺ
Makes sense purely for the dev convience (except me)
Pobiega
Pobiegaβ€’3mo ago
you have a point. Look at the Go programming language as an example
Merineth πŸ‡ΈπŸ‡ͺ
But yea i got a decent basic understanding of delegates now
Pobiega
Pobiegaβ€’3mo ago
its intentionally kept simple and low amount of features
Merineth πŸ‡ΈπŸ‡ͺ
Not sure how i'm gonna practice it tho
Pobiega
Pobiegaβ€’3mo ago
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?
Merineth πŸ‡ΈπŸ‡ͺ
We were only given one exercise which includes lambda ... and it's kind of complex
Pobiega
Pobiegaβ€’3mo ago
here is a screenshot of my ConsoleHelper methods I use when I write console apps, as inspiration. Plenty of lambdas, generics and delegates here
No description
Merineth πŸ‡ΈπŸ‡ͺ
public class Command<T> : ICommand
{
private T target;
private Action<T> command;

public Command(T target, Action<T> command)
{
this.target = target;
this.command = command;
}
public void Execute()
{
command(target);
}
public class Command<T> : ICommand
{
private T target;
private Action<T> command;

public Command(T target, Action<T> command)
{
this.target = target;
this.command = command;
}
public void Execute()
{
command(target);
}
No description
Merineth πŸ‡ΈπŸ‡ͺ
Am 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!
Want results from more Discord servers?
Add your server