I am trying to read some code on the internet, but still cannot figure it out.
The code is:
private delegate string GetAString();
static void Main()
{
int x = 40;
GetAString firstStringMethod = new GetAString(x.ToString);
Console.WriteLine(firstStringMethod());
}
My question is "delegate string GetAString()" does not need parameters, but when it is instantiated, it has the x.ToString parameter.
Why? Can anyone explain this?
Thanks.
A delegate is a special type of variable that can hold a reference to a method (not the result of the method but the method itself), allowing it to be passed around and invoked in places where you perhaps don't have access to the object the method belongs to.
From the docs:
Represents a delegate, which is a data structure that refers to a static method or to a class instance and an instance method of that class.
Your code:
GetAString firstStringMethod = new GetAString(x.ToString);
Note the lack of () at the end of x.ToString. We're not calling x.ToString() here. We're creating a GetAString and passing x.ToString (which is a method that satisfies the signature required by the delegate).
This means that when we call firstStringMethod() it will call x.ToString() and proxy the result to you.
Consider another example:
public delegate int Operation(int a, int b);
We could define multiple methods:
public int Sum(int a, int b)
{
return a + b;
}
public int Multiply(int a, int b)
{
return a * b;
}
And then switch according to user input:
Operation o;
switch (Console.ReadLine())
{
case "+":
o = new Operation(Sum);
break;
case "*":
o = new Operation(Multiply);
break;
default:
Console.WriteLine("invalid operation");
return;
}
Console.WriteLine(o(4, 3));
If the user inputs "+" then the result will be 7, while inputting "*" will result in "12".
You can see from this example that we're not passing the arguments of Sum or Multiply when we instantiate o. We're simply passing the method. We then use the delegate to supply the arguments and get the result.
Example if user input is +
Example if user input is *
Related
I have a function that repeatedly calls another function.
The second function has a bool parameter that changes the way it behaves, so when I call the first function I want to have a parameter that specifies the way the second function behaves.
void Function1(int n, bool differentBehavior = false)
{
int a = Function2(n, differentBehavior);
int b = Function2(1, differentBehavior);
int c = Function2(2, differentBehavior);
return a + b + c;
}
int Function2(int x, bool differentBehavior)
{
if (!differentBehavior) // do something
else // do something else
}
The code itself is obviously an example (in reality the second function is called over 20 times and for code readability I would love to not have to specify the second parameter every time), but I put it there to explain what I'm currently doing. Is there no better way to achieve this?
You can introduce a local function to capture the second argument like so:
int Function1(int n, bool differentBehavior = false)
{
int func(int n) => Function2(n, differentBehavior);
int a = func(n);
int b = func(1);
int c = func(2);
return a + b + c;
}
This is called "partial function application". See more here:
https://codeblog.jonskeet.uk/2012/01/30/currying-vs-partial-function-application/
While C# doesn't support true function Currying nor first-class partial function application, you can always
use a new locally scoped function (aka a local function) to wrap your Function2 with predefined arguments... which is conceptually almost the same thing as partial application, just without referential-transparency, and awkward delegate types.
Anyway, if you want to pass the outer Function1's differentBehavior argument value to Function2 then you will need to use a closure, which will capture the variable, but this will introduce slight runtime performance complications: as a closure generally means a GC heap allocation and copying function local state from the stack onto the heap and yada yada.
However, if you're only using constant parameter values - or you're okay with using different wrappers for different predefined argument values, then you can use a static local function (requires C# 8.0 or later) which prevents you from unintentionally creating a closure.
For example:
void Function1(int n, bool differentBehavior = false)
{
// Look ma, no closure!
static int PartiallyAppliedFunc2_False(int x) => Function2( x: x, differentBehavior: false );
static int PartiallyAppliedFunc2_True(int x) => Function2( x: x, differentBehavior: true );
int a = PartiallyAppliedFunc2_False(n);
int b = PartiallyAppliedFunc2_False(1);
int c = PartiallyAppliedFunc2_True(2);
return a + b + c;
}
int Function2(int x, bool differentBehavior)
{
if (!differentBehavior) // do something
else // do something else
}
One thing to look at when a lot of parameters are being passed on the stack is whether there is some higher-level state that could be represented by a member variable of the class.
Here's some code for the most basic kind of state machine. This general approach might help solve the problem you're having:
class Program
{
enum Behaviors
{
BehaviorA,
BehaviorB,
BehaviorC,
}
static Behaviors State { get; set; }
static void Main(string[] args)
{
for (State = Behaviors.BehaviorA; State <= Behaviors.BehaviorC; State++)
{
Console.WriteLine($"Function returned { Function1(0)}");
}
int Function1(int n)
{
int a = Function2(n);
int b = Function2(1);
int c = Function2(2);
return a + b + c;
}
int Function2(int x)
{
switch (State)
{
case Behaviors.BehaviorA:
return x * 10;
case Behaviors.BehaviorB:
return x * 20;
case Behaviors.BehaviorC:
return x * 30;
default:
throw new NotImplementedException();
}
}
}
}
Want feedback if i`m correct here?
Use void if you are not returning anything in a method,
otherwise
Name your data types used in the method criteria before method name.
use Return in the method before the calculation or output.
So something like this.
static int MyMethod(int x)
{
return 5 + x;
}
static void Main(string[] args)
{
Console.WriteLine(MyMethod(3));
}
// Outputs 8 (5 + 3)
What if my method has ints and doubles?
Do I write as follows? (another words do I have to mention every type i`m using prior to the method name?
static int double myMethod (int x, double y)
Even with that I dont know when is a method void? It seems my methods all return values.
Isnt the following returning the values of the arguments? So why should I label it void?
static void MyMethod(string fname, int age)
{
Console.WriteLine(fname + " is " + age);
}
static void Main(string[] args)
{
MyMethod("Liam", 20);
MyMethod("Jenny", 25);
MyMethod("Tom", 31);
}
I can only think that a void means there is no new calculation being done in the actual method body, passing arguments into a method and spitting them out for user viewing does not mean its "returning a value", I dont know what i`m talking about.
Let's be completely clear about what these bullets mean.
Use void if you are not returning anything in a method, otherwise
In this context, "return" means that the method provides an output that can be assigned to a variable by the caller. For example
int Return10()
{
return 10;
}
...allows the caller to do this:
int x = Return10();
Console.WriteLine(x); //Outputs "10"
A method should "return" void when its results cannot be assigned. For example, if the results are printed on the screen.
void Print10()
{
Console.WriteLine("10"); //Prints 10 to the screen
}
...which allows the caller to do this:
Print10();
You cannot assign it because it doesn't return anything. This doesn't work:
int x = Print10(); //Compiler error
Name your data types used in the method criteria before method name.
A method can return exactly one value or object. So "types" here is wrong. You can only specify one type.
Use return in the method before the calculation or output.
This is a little misleading. The return keyword should be followed by an expression which can be assigned.
int Return10()
{
return 10 + 10; //Is okay because it's an expression and could be assigned
}
int Return10()
{
var x = 10 + 10;
return x; //This is also okay; in fact it does exactly the same thing as the previous example
}
int Return10()
{
return Console.WriteLine("10"); //Compiler error; can't be assigned to anything.
}
By the way, a method can also output something and return it:
int WriteAndReturn10()
{
int x = 10;
Console.WriteLine(x);
return x;
}
I am going to address the following
What if my method has ints and doubles? Do I write as follows?
(another words do I have to mention every type i`m using prior to the
method name?
There are no built in ways or syntax to return more than one type from a method as the return parameter.. This is basically historical and has been this way since dinosaurs roamed the earth.
However, there are lots of options that achieve the same result. For instance, you could use a custom struct, you could use out parameters, you could use a class, or a delegate parameter of some kind. However, a modern succinct approach might be to use a Value Tuple:
static (int someInt, double someDouble) myMethod (int x, double y)
{
return (x,y);
}
Fun Fact : even though this looks like you a returning more than one type, you are actually just invoking a special syntax that wraps your return parameters in a single type of struct
Usage
var result = myMethod(1,2.2);
Console.WriteLine(result.someInt);
Console.WriteLine(result.someDouble);
Or if you want to get fancy, you can use the newer deconstructed syntax
var (someInt, someDouble) = myMethod(1,2.2);
Console.WriteLine(someInt);
Console.WriteLine(someDouble);
Additional Resources
return (C# Reference)
Methods (C# Programming Guide)
Tuple types (C# reference)
out parameter modifier (C# Reference)
ref (C# Reference)
Using Delegates (C# Programming Guide)
I have a question regarding method overlading given below
Fun1(int a);
Fun1(ref int a);
Is this method overloading? IF Yes then WHY and if No then WHY?
As per documentation:
Methods can be overloaded when one method has a ref or out parameter and the other has a value parameter
So the answer to your question is yes, but why?
As per definition of function overloading:
Function overloading (also called method overloading) is a programming concept that allows programmers to define two or more functions with the same name and in the same scope. Each function has a unique signature (or header), which is derived from:
function/procedure name
number of arguments
arguments' type
arguments' order
When you are passing a parameter without using the ref keyword you are actually passing a reference to the variable thus the type of argument is different from that when passed without ref keyword.
public void function(ref int abc)
{
Console.WriteLine("Result Ref: " + abc);
}
public void function(int abc)
{
Console.WriteLine("Result: " + abc);
}
Thus the signature of the above two functions is not the same as the type of argument passed to the both is not the same.
Hope I was able to satisfy you with my answer :).
Also I would like to add another point to the discussion that overloading is not possible in case of using out with one function and ref with another as in this case both the types are considered as same so no overloading in the following case:
public void function(ref int abc)
{
Console.WriteLine("Result Ref: " + abc);
}
public void function(out int abc)
{
abc = 1221;
Console.WriteLine("Result Out: " + abc);
}
1) Fun1(int a);
2) Fun1(ref int a);
1 and 2 are different functions. 1 - pass by value, 2 - pass by reference.
For example:
public static void Func(int i)
{
i++;
Console.WriteLine("int a = {0}", i);
}
public static void Func(ref int i)
{
i++;
Console.WriteLine("ref int a = {0}", i);
}
static void Main(string[] args)
{
int a = 9;
Func(ref a);
// Func(a);
Console.WriteLine("a = {0}", a);
Console.Read();
}
output:
ref int a = 10
a = 10
it means that a is passed by reference and function Func(ref int i) can change its value.
in second case when you call Func(a) in Main function result is:
int a = 10
a = 9
It means that a is passed by value.
You can implement both functions in one class․
Here i have three functions; passing a reference from function 1 to function 2.So in function 2, a is a reference. Then why it is not allowed to pass this same reference to function 3? without using the keyword ref
Function 1:
public void funReadA()
{
double a=10;
//read value for a
funReadB(ref a);
}
Function 2 :
public void funReadB(ref double a)
{
double b = 25;
a = 11;
// sum(a, b);this method call is not allowed
sum(ref a, b);// why ref a is required? a is already a reference na?
}
Function 3:
public double sum(ref double a,double b)
{
return a += b;
}
The ref keyword on the call site is required mostly to make sure the person who wrote the calling code is aware that he is passing a reference, and so that the value could change.
It's not strictly necessary from a programming language point of view, but it's a good idea from a programmer point of view.
public delegate int NumberChanger(int n);
class Program
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
static void Main(string[] args)
{
//create delegate instances
NumberChanger nc1 = new NumberChanger(AddNum);
//calling the methods using the delegate objects
nc1(25);//It is return interger value,but WHY NOT SHOW ERROR. ...(1)
int result=nc1(25); .............................................(2)
Console.WriteLine("Value of Num: {0}", result);
Console.ReadKey();
}
}
Statement 1 and statement 2 are calling same method. but in statement 1 is not handle return. why it is not throw error.
You are not required to use a value just because it is returned from a method.
Just as you can call Console.ReadKey(); without using the ConsoleKeyInfo value that is returned, you can call nc1(25); without using the integer that it returns.
This is the same for calling methods directly and using a delegate to call a method.
To be allowed to ignore the return value is useful for example for chaining method calls.
The StringBuilder.Append method returns the StringBuilder object so that you can chain calls:
sb.Append('<').Append(num).Append('>');
The last Append call also returns the StringBuilder, but that value is ignored.
Why should the compiler return an error? If you called
AddNum(25)
would you receive an error? No? then for a simmetrical reason, even calling a delegate ignoring its result shouldn't be an error
(as a sidenote, in many C compilers there is a flag to produce a warning (a warning, not an error) if a function that returns a value is called and the value is ignored, for example in gcc it's -Wunused-result. There is nothing similar in C#)