If I have function like this
double GetExpression(int x, int y, int z)
{
return x * y + z;
}
is it possible to modify it somehow, to not return result immediately only some object which is expression and then evaluate it this way:
var expression = GetExpression(1,2,3);
double result = expression.Execute() or expression.Evaluate()
other words just return function
?
Yes!
Func<double> GetExpression(int x, int y, int z)
{
return () => x * y + z;
}
use as:
var expression = GetExpression(1,2,3);
double result = expression();
Well, you could use delegates, and return a Func<double>:
Func<double> GetExpression(int x, int y, int z)
{
return () => x * y + z;
}
var expression = GetExpression(1,2,3);
double result = expression(); // Or expression.Invoke()
Is that what you were looking for?
Now each time you call expression() it will execute the code in the lambda expression. You can observe that if you use code which doesn't just return the same value each time. For example:
Func<int> GetExpression()
{
Random rng = new Random();
return () => rng.Next(10);
}
var expression = GetExpression();
for (int i = 0; i < 10; i++)
{
Console.WriteLine(expression());
}
That will print 10 random numbers in the range [0, 10). Note that this will only create one instance of Random (avoiding a common problem) - each time you call expression() it will call the Next() method on the same instance. The constructor for Random is called in the "normal" part of the method - it's not in the lambda expression. So that gets executed when you first call the GetExpression method (even if you never call expression() afterwards).
Note however that the arguments to your GetExpression were still passed by value though, and are captured by the lambda express. So consider this:
Func<int> GetExpression(int a, List<int> b)
{
return () => a + b.Count;
}
int x = 10;
List<int> list = new List<int> { 1, 2, 3 };
var expression = GetExpression(x, list);
Console.WriteLine(expression()); // 13
x = 20;
list.Add(100);
Console.WriteLine(expression()); // 14
Here the value of the list variable has been captured, so changes the the object that the value refers to are visible in the lambda expression, but changes to the x variable itself are not visible in the lambda expression. (Likewise if you had list = new List<int>(); that change wouldn't be visible...
To expand on Jon Skeet's answer, about capturing variables, if you didn't want to, you could do something like this:
double GetExpression(int x, int y, int z)
{
return x * y + z;
}
Func<int, int, int, double> expression = GetExpression;
for (int i = 0; i < 10; i++)
Console.WriteLine("{0}", expression(i, i+1, i+2));
Which avoids modifying the existing code (in case you wanted to point to a function you didn't have control over), and avoids capturing values outside of the lamda.
Related
In the Sunday evening I have been watching some conferences this time I get hands on this one Conference Link
Where I found out pretty interesting think there is simple code example:
struct Point
{
private double x;
public double X { get => x; set => x = value; }
private double y;
public double Y { get => y; set => y = value; }
public Point(double x, double y) => (this.x, this.y) = (x, y);
public void SwapCode() => (X, Y) = (Y, X);
}
In Main:
var point = new Point(10.0, 11.0);
Console.WriteLine($"x: {point.X}, y: {point.Y}");
point.SwapCode();
Console.WriteLine($"x: {point.X}, y: {point.Y}");
And there is output of this :
x: 10, y: 11
x: 11, y: 10
So there is some questions:
How does it works ?
What I mean by that is Tuples should be translate into Tuple<T, K> which should be initialize with copy of the values but there it assign values to the variables at least for me it's kind of counter intuitive.
And i wonder if it's just sugar syntax think or there is happen some magic under this what make perfect sense but I can't spot it out?
Firstly structs should be immutable. Even though you can do this, you probably shouldn't.
Secondly, your SwapCode is actually doing this, as seen here.
public void SwapCode()
{
double num = Y;
double num2 = X;
double num4 = X = num;
num4 = (Y = num2);
}
Yeah, it's a little strange. However, it's just a little syntactic magic introduced in C#7. What it is actually doing is using a deconstruct method (the terminology .Net uses) to provide a set of out arguments for each of the params you want to extract. In this case, it's the properties/field you supplied!
To see it a little clearer, consider these two functionally equivalent code blocks
(int x, int y) asd = (1, 2); // create a Value Tuple
(int x, int y) = asd; // deconstruct it
(x, y) = (x, y); // assign to the deconstructed type
// All the above now has the swapped values
// they are all pointing to the same variables/memory
// You could even take this further by
x = 10;
y = 11;
// Once again, x and y, asd, and (x, y) all have the same values
// Because they are the same
// ----------------------------------------------------
int x = 1;
int y = 2;
(x, y) = (y, x); // we are just deconstructing our original variables
// All the above now has the swapped values
// they are all pointing to the same variables/memory
Note : As you can see, this is also a slightly more succinct way of swapping 2 variables as you don't have to use a temp variables, your friendly CLR does it for you
Anyway, you shouldn't be doing this with a struct anyway, they really should be immutable for various reasons
Out of curiosity I've been looking into delegate methods and am interested in getting the name of the current delegate method that is being used (just for fun, really).
The code I have is as follows (with the current/desired outputs):
private delegate int mathDelegate(int x, int y);
public static void Main()
{
mathDelegate add = (x,y) => x + y;
mathDelegate subtract = (x,y) => x - y;
mathDelegate multiply = (x,y) => x * y;
var functions = new mathDelegate[]{add, subtract, multiply};
foreach (var function in functions){
var x = 6;
var y = 3;
Console.WriteLine(String.Format("{0}({1},{2}) = {3}", function.Method.Name, x, y, function(x, y)));
}
}
/// Output is:
// <Main>b__0(6,3) = 9
// <Main>b__1(6,3) = 3
// <Main>b__2(6,3) = 18
/// Desired output
// add(6,3) = 9
// subtract(6,3) = 3
// multiply(6,3) = 18
Does anyone know of any way(s) I could achieve this? Thanks.
Your methods are anonymous delegates, so the the compiler gives each of them a name that doesn't have any meaningful connection back to the variable name. If you want them to have better names then make them actual methods:
public int Add(int x, int y)
{
return x + y ;
}
etc. Then reference them by name:
var functions = new mathDelegate[]{this.Add, this.Subtract, this.Multiply};
Note that the this. is optional but illustrates that they are class members rather than local variables.
I'm using this code to build my 3d surface plot in each point, but I have a problem that I need to parametrize my function so t variable will be looped from 0 to T value, but I can't figure it out how can I do it inside the delegate?
edited the first block for more clarity:
/*this is code for building 3d surface plot, parameter delegate is counting Z
value in each (x, y) point.
x, y are axis variables. t is constant here*/
new ILPlotCube()
{
new ILSurface((x, y) => (float) (1/(x+y+t))
}
Resulting pseudocode is something like:
float functionValue = 0;
for (double t = 0; t < T; t + deltaT)
{
/*t is loop parameter here*/
functionValue += (float) (1/(x+y+t));
}
return functionValue;
If you don't need an Expression Tree, then it should be:
Func<float, float, float> func = (x, y) =>
{
float functionValue = 0;
for (double t = 0; t < T; t += deltaT)
{
/*t is loop parameter here*/
functionValue += (float)(1 / (x + y + t));
}
return functionValue;
};
Note that I had to change the t + deltaT adder of the for
From there you can
new ILSurface(func);
This is a statement lambda, because it uses { ... } code after the =>. See https://msdn.microsoft.com/library/bb397687.aspx statement lambdas
I have a method declaration like this:
public int myMethod(int x, out int y, out int z)
{
int k;
foreach(int i in someList)
{
if(anotherMethod(out k))
{
z = k;
}
else
{
z = 0;
}
}
y = someValue;
return anotherValue;
}
but I get this compiling error
The out parameter 'z' must be assigned to before control leaves the current method
If someList is empty, it will never enter the foreach loop, and therefore z will never be assigned. To resolve this, ensure that z is given a value regardless of of the contents of someList:
public int myMethod(int x, out int y, out int z)
{
z = 0; // or whatever default value you like
...
}
However, you should probably consider refactoring this code. It's likely there's a better way to accomplish this. If you'd really like to return 3 different int values, you might consider using a Tuple<int, int, int> or creating a custom data type to represent the value.
Reason : out paramaeters must be initialised before returning from the function.
You are assigning value for parameter z inside if block so compiler
could not identify whether it can be initialized or not hence initialize
your parameter z before if block as below:
public int myMethod(int x, out int y, out int z)
{
int k;
z=0;
foreach(int i in someList)
{
if(anotherMethod(out k))
{
z = k;
}
else
{
z = 0;
}
}
y = someValue;
return anotherValue;
}
If someList is empty, then z will never be assigned a value, which violates it's being an out variable. Remove the out constraint, or reconfigure your function logic.
Lets say I have the following code:
delegate int MyDel (int n); // my delegate
static int myMethod( MyDel lambda, int n) {
n *= n;
n = lambda(n);
return n; // returns modified n
}
This way, having different lambda expression I can tune the output of the Method.
myMethod ( x => x + 1, 5);
myMethod ( x => x - 1, 5);
Now, if I don't want to do any aritmethic in lambda expression, I could use:
myMethod ( x => x, 5); // and lambda will simply return x
My question is, is there a way to use the lambda expresion with 'params' optional properties? Maybe somehow embedding my delegate in array?
static int myMethod (int n, params MyDel lambda) {
Does this work?
EDIT
Sorry, was doing this with one eye, let me rephrase that.
static int myMethod (int n, params MyDel[] lambdas) {
Yes you can.
delegate int MyDelegate(int n);
static void MyMethod(int n, params MyDelegate[] handlers)
{
for (int i = 0; i < handlers.Length; i++)
{
if (handlers[i] == null)
throw new ArgumentNullException("handlers");
Console.WriteLine(handlers[i](n));
}
}
static void Main(string[] args)
{
MyMethod(1, x => x, x => x + 1);
Console.Read();
}
Output:
1
2