Click here to Skip to main content
15,881,719 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello Code Project Gurus

I know it is possible to have delegates operate with values that are known at the time the delegate is called - that's simply a parameter
e.g.
   Func<double, double> areaOfCircle = r => Math.PI * Math.Pow(r, 2); 
   Func<double, double> diameterOfCircle = r => 2 * Math.PI * r;
   
   var iNeed = diameterOfCircle;
// -----------------------------
   Console.WriteLine(iNeed(5));    // output is 31.4159265358979
   Console.WriteLine(iNeed(10));   //           62.8318530717959
		
   iNeed = areaOfCircle; 
// ---------------------
   Console.WriteLine(iNeed(5));    // output is 78.5398163397448
   Console.WriteLine(iNeed(10));   //           314.159265358979

I am wondering if there is any way to dynamically create delegates so that each delegate operates using values that are known at runtime when the delegate is created (not when the delegate is called).

So, using the example above, is there a way tell areaOfCircle to use some other factor rather than pi? Something akin to
   Func<double, double> areaOfCircle = r => ::factor:: * Math.Pow(r, 2); 
   Func<double, double> diameterOfCircle = r => 2 * ::factor:: * r;
   
   var iNeed = diameterOfCircle(factor::3);   
// ----------------------------------------
   Console.WriteLine(iNeed(5));    // output is 30
   Console.WriteLine(iNeed(10));   //           60
		
   iNeed = areaOfCircle(factor::3.14); 
// -----------------------------------
   Console.WriteLine(iNeed(5));    // output is 78.5
   Console.WriteLine(iNeed(10));   //           314

Again, I know that a simple example like this is easily solvable by passing the factor to each function in the Console.WriteLine calls. But instead, imagine that the assignment to iNeed and the calls to iNeed are occurring in separate methods, or even classes; that once iNeed is assigned, it is passed as the return value to a calling class that sticks it in a List, which gets called by another class to execute the function... normal, everyday type of stuff.

What I am looking for is a way to set up the functions to operate with a certain factor when the assignment to iNeed is made. Is such a thing possible?

What I have tried:

Searching the net.
Reading MS documentation on delegates, anonymous delegates, dynamic variables, etc.
Posted
Updated 7-Dec-18 3:09am
v2

Something like this would work:
C#
Func<double, Func<double, double>> factoredAreaOfCircle = factor => r => factor * Math.Pow(r, 2);
Func<double, Func<double, double>> factoredDiameterOfCircle = factor => r => 2 * factor * r;

Func<double, double> iNeed = factoredDiameterOfCircle(3);
Console.WriteLine(iNeed(5));  // Output is 30
Console.WriteLine(iNeed(10)); // Output is 60
		
iNeed = factoredAreaOfCircle(3.14); 
Console.WriteLine(iNeed(5));  // Output is 78.5
Console.WriteLine(iNeed(10)); // Output is 314

Currying vs partial function application | Jon Skeet's coding blog[^]
 
Share this answer
 
Comments
C Pottinger 7-Dec-18 11:48am    
T E R R I F I C ! ! !
Thank you, Richard. This is exactly what I wanted.

Last night I was thinking about how I had constructed my example for the question and realized that I could have done better. When I saw your answer this morning I tested it using my new model:
Func<double, Func<double, double>> areaOfCircle = factor => r => { Console.WriteLine("area factor is {0}", factor); return (double)(factor * Math.Pow(r, 2)); }; 
Func<double, Func<double, double>> diameterOfCircle = factor => r => { Console.WriteLine("diameter factor is {0}", factor); return (double)(2 * factor * r); };		

var funcList = new List<Func<double, double>>() 
{
	diameterOfCircle(Math.PI),
	areaOfCircle(Math.PI),
	diameterOfCircle(3),
	areaOfCircle(3.14),
};

foreach(var iNeed in funcList)
{
	//Console.WriteLine(iNeed(5));
	Console.WriteLine(iNeed(10));
}

It worked perfectly.

And the article by Jon Skeet explained the workings and background very well.
Thanks again.
You cannot change the delegate definition at runtime.

A delegate is nothing but a pointer to a function. The parameter list of the delegate must match the parameter list of the function that it points to. If it doesn't you can unbalance the stack as the call is pushing parameters on the stack and the function you're calling is popping them off the stack not as they were pushed on.

The concept is called "self modifying code" and is stupid difficult to implement properly in production quality code. I don't ever recommend doing it.

What you are really talking about is just adding an optional parameter to your function, the default value of which is PI.
C#
double CalculateAreaCircle(double r, double factor = Math.PI);
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900