Func delegate doesn't chain methods - c#

Lets imagine simple delegate calls:
void Main()
{
Func<int, int, string> tfunc = null;
tfunc += Add; // bind first method
tfunc += Sub; // bind second method
Console.WriteLine(tfunc(2, 2));
}
private string Add(int a, int b)
{
return "Add: " + (a + b).ToString();
}
private string Sub(int a, int b)
{
return "Sub: " + (a - b).ToString();
}
The result of this program is:
Sub: 0
So, why Add method was not called? I'm expecting to call Method Add, and then method Sub.

Add was correctly chained and called, take a look at the result of
void Main()
{
Func<int, int, string> tfunc = null;
tfunc += Add; // bind first method
tfunc += Sub; // bind second method
Console.WriteLine(tfunc(2, 2));
}
private string Add(int a, int b)
{
Console.WriteLine("Inside Add");
return "Add: " + (a + b).ToString();
}
private string Sub(int a, int b)
{
Console.WriteLine("Inside Sub");
return "Sub: " + (a - b).ToString();
}
It is:
Inside Add
Inside Sub
Sub: 0
What is not chained, because there is no way to access it, is the result of the Add method. Delegates that return a value, in case of chaining, return the value of the last method invoked, that is the last method that was added to the delegate.
This is specified in part 15.4 of the C# 4.0 language specification
Invocation of a delegate instance whose invocation list contains
multiple entries proceeds by invoking each of the methods in the
invocation list, synchronously, in order. ...
If the delegate invocation includes output parameters or a
return value, their final value will come from the invocation of the
last delegate in the list.

The problem is that the return value is not passed between the method invocations, so the output only captures the last string returned. I.e. the return of Add is lost.

Related

Call function with a parameter from another function

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();
}
}
}
}

A simple question about delegate instantiation

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 *

Can ref and Out keyword can decide method overloading

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․

C# - Delegate with any amount of custom parameters [duplicate]

This question already has answers here:
How can I design a class to receive a delegate having an unknown number of parameters?
(6 answers)
C# How to call a method with unknown number of parameters
(3 answers)
Closed 5 years ago.
I want a delegate that I can store in a variable for later use that has custom amounts of custom parameters. What I mean by that, is that I want to pus it different methods with different return types and different arguments. For example:
public double Sum (double a, double b) {return a + b;}
public char GetFirst (string a) {return a[0];}
public bool canFlipTable (object[] thingsOnIt) {return thingsOnIt.Length <= 3;}
DoTheThing<double> thing1 = new DoTheThing<double>(Sum);
DoTheThing<char> thing2 = new DoTheThing<char>(GetFirst);
DoTheThing<bool> thing3 = new DoTheThing<bool>(canFlipTable);
thing1.Call(10.3, 5.6); //15.9
thing2.Call("Hello World"); //'H'
thing3.Call(new object[] {new Lamp(), new Laptop(), new CoffeMug()}); //true
I figured out the return value and the call method already, but I'm having a problem with storing the methods
If I use "public DoTheThing(Action method)" it says, that the arguments doesn't match
I even tried with a delegate that had "params object[] p" as arguments, but it didn't work either
EDIT:
I forgot to tell, the method WILL always have a return type and at least 1 parameter
EDIT 2:
My goal is creating a wrapper class, that caches outputs from very expensive methods and if the same thing gets called again, it returns the cached value.
Of course I could solve this with an interface, but I want to do this with classes that I can't simply edit and I want to make this felxible too, so having the cache at the same place where I call the method is not an option either.
My code sofar:
public class DoTheThing <T>
{
public delegate T Method(params object[] parameters);
Func<T> method;
ParameterInfo[] pInfo;
public DoTheThing (Method method)
{
this.method = method;
Type type = typeof(Method);
MethodInfo info = type.GetMethod ("Invoke");
if (info.ReturnType != typeof(T)) {
throw new Exception ("Type of DoTheThing and method don't match");
}
pInfo = info.GetParameters ();
}
public T Call (params object[] parameters) {
if (parameters.Length != pInfo.Length) {
throw new Exception ("Wrong number of arguments, " + parameters.Length + " instead of " + pInfo.Length);
return default(T);
}
for (int i = 0; i < parameters.Length; i++) {
if (pInfo[i].ParameterType != parameters[i].GetType()) {
throw new Exception ("Wrong parameter: " + parameters [i].GetType () + " instead of " + pInfo [i].ParameterType + " at position: " + i);
return default(T);
}
}
return (T)method.DynamicInvoke (parameters);
}
}
Before trying to figure how to do it, I would really question the problem that leads me to have such a kind of delegate. I would bet if I knew the context better, there would be a solution that would eliminate your requirement.
Having that said, delegates are classes that inherit from MulticastDelegate. In fact, when you declare a delegate, you are creating a new class type with MulticastDelegate as its base class. That means the following code works:
public static double Sum(double a, double b)
{
return a + b;
}
public static string SayHello()
{
return "Hello";
}
static void Main(string[] args)
{
MulticastDelegate mydel = new Func<double, double, double>(Sum);
var ret = mydel.DynamicInvoke(1, 2);
System.Console.WriteLine(ret);
mydel = new Func<string>(SayHello);
ret = mydel.DynamicInvoke();
System.Console.WriteLine(ret);
mydel = new Func<string, int, string> ((s, i) => {
return $"Would be {s}, {i} times";
});
ret = mydel.DynamicInvoke("Hello", 5);
System.Console.WriteLine(ret);
}
Because "mydel" variable is of the base class type (MulticastDelegate), we can actually use it with any kind of delegate and invoke it with arbitrary parameters. If they don't match the method being invoked, it will throw at runtime.

Clarification about delegates

What is the below code doing? I think the pointer will be changed to the multiply method.
But what is "+=" doing here. I am confused.
delegate int calc(int a , int b);
static void Main(string[] args)
{
calc c = new calc(Add);
c += new calc(Multiply);
Console.WriteLine(c(3, c(4, 2)));
Console.Read();
}
public static int Add(int a, int b)
{
return (a + b);
}
public static int Multiply(int a, int b)
{
return (a * b);
}
The + and += operator
Similar to how you use the + operator to add values, you can use the += operator to both add and assign back to the same value.
An example of these operators applied to ints:
int a = 5;
a += 7; // a is now 12
a = a + 11;
Console.WriteLine(a);
24
Combining delegates
As AVD mentioned, you use the + and += operators to combine delegates.
When you apply these operators to delegates, you aren't doing a mathematical "sum" or "sum and assign", like my example with ints. Instead you are modifying a list of methods to be called when you invoke the delegate.
From that article:
Delegates can be combined such that when you call the delegate, a whole list of methods are called - potentially with different targets
So when you add/combine delegates, you'll end up calling multiple methods.
If you change your code to:
public static int Add(int a, int b)
{
Console.WriteLine("From Add");
return (a + b);
}
public static int Multiply(int a, int b)
{
Console.WriteLine("From Multiply");
return (a * b);
}
Then you will see this output when you run the program:
From Add
From Multiply
From Add
From Multiply
24
This is because:
You combined the Add and Multiply delegates, so both get called when you call c(x, y)
Multiply is the last delegate you added to that chain of delegates
You are calling c(x, y) twice. This is similar to if you had called: Multiply(3, Multiply(4, 2))
Return values from combined delegates
That point about the last delegate you added to the chain is also mentioned in the article:
If a delegate type is declared to return a value (i.e. it's not declared with a void return type) and a combined delegate instance is called, the value returned from that call is the one returned by the last simple delegate in the list.
The last method you added to the chain was Multiply, so all other return values are thrown out, and only the return value from Multiply is used when you call c(x, y).
You can see this demonstrated in your program. 3 * 4 * 2 is 24, which is your program's output. None of your calls to Add impact the final result.
+= is like appending multiple calls to the delegate object. Since its a multicast delegates, you can append multiple destination calls to the a single delegate. To append to a delegate, you need new delegate objects. And thats whats been doing in the second line.
Its similar to,
CalcDelegate C1, C2;
C1 = new CalcDelegate(Add);
C2 = new CalcDelegate(Multiply);
C1 = C1 + C2;
Its called Combining the delegates.
You can think of delegates as a cross between value types (like int or double) and arrays of method addresses.
You know that if you write this code:
var x = 5;
var y = x + 2;
y += 3;
Then afterwards x == 5 & y == 10 even though y had an intermediate value of 7 this was "thrown away" when the final assignment occurred.
Quite clearly the final value of y isn't 3.
In your code you wrote this:
calc c = new calc(Add);
c += new calc(Multiply);
As with y, the final value of c isn't Multiply. It's really more like this:
c == { Add, Multiply }
When you then call something like c(4, 2) you are effectively calling both Add & Multiply and because the delegate returns a value you only get back the final delegate's value - in this case from Multiply - and that's what makes it appear that the "pointer" changed to the Multiply method.
You could try adding in this code before you call c:
c -= new calc(Multiply);
and this will effectively return c back to this:
c == { Add }
And this is why delegates appear to behave like arrays of method addresses.
Now if you change your Add & Multiply methods to look like this:
public static int Add(int a, int b)
{
Console.WriteLine("Add({0}, {1})", a, b);
return (a + b);
}
public static int Multiply(int a, int b)
{
Console.WriteLine("Multiply({0}, {1})", a, b);
return (a * b);
}
you can then watch the calls as they occur. Your original code runs like this:
Add(4, 2)
Multiply(4, 2)
Add(3, 8)
Multiply(3, 8)
24
I hope this helps.

Categories