I have a part of code which is repeated multiple time in a function. However I'd like to make a function of it, but I'd like it to know the variables of my function so it can modify them without the need to pass them (because there is a lot).
example of what I want to accomplish
static void Main(string[] args)
{
int x = 0
subfunction bob()
{
x += 2;
}
bob();
x += 1;
bob();
// x would equal 5 here
}
Use Action:
static void Main(string[] args)
{
int x = 0;
Action act = ()=> {
x +=2;
};
act();
x += 1;
act();
// x would equal 5 here
Console.WriteLine(x);
}
You could wrap your parameters into a class.
public class MyParams
{
public int X { get; set; }
}
public static void bob(MyParams p)
{
p.X += 2;
}
static void Main()
{
MyParams p = new MyParams { X = 0 };
bob(p);
p.X += 1;
bob(p);
Console.WriteLine(p.X);
}
This is roughly what the lambda answers are doing behind the scenes.
You can do this by using a lambda expression:
public static void SomeMethod () {
int x = 0;
Action bob = () => {x += 2;};
bob();
x += 1;
bob();
Console.WriteLine(x); //print (will be 5)
}
The lambda expression is the following part() => {x += 2;}. The () denotes that the action takes no input at all. Between accolades, you can then specify the statements that should be executed. Variables not defined on the left of the lambda expression (llike x) are bounded like the normal rules of scoping in the C/C++/Java language family. Here x thus binds with the local variable x in SomeMethod.
Action is a delegate, it refers to a "method", and you can call it as a higher-order method.
Note that your code is not C#. You cannot write int main as main method.
Demo (Mono's C# interactive shell csharp)
$ csharp
Mono C# Shell, type "help;" for help
Enter statements below.
csharp> public static class Foo {
>
> public static void SomeMethod () {
> int x = 0;
> Action bob = () => {x += 2;};
> bob();
> x += 1;
> bob();
> Console.WriteLine(x);
> }
>
> }
csharp> Foo.SomeMethod();
5
Related
I am working on an application where we need to log entire statement of anonymous (lambda) function.
What it means is that the "LogAction" method should log all the statements that are passed as action.
protected void LogAction(Action action)
{
/*
Log the statement(s) passed to this method i.e. should print
var a = 10;
var b = 20;
Console.WriteLine($"Sum of {a} and {b} is {a+b}");
*/
}
LogAction(() =>
{
var a = 10;
var b = 20;
Console.WriteLine($"Sum of {a} and {b} is {a+b}");
});
You can use the Expression class in C#:
Expression<Action> ex = () => System.Console.WriteLine("Hello world");
Console.WriteLine(ex.ToString());
The above code will print () => WriteLine("Hello world") on the console. This should help enough for debugging purposes. Unfortunately it does not provide as much flexibility as one would expect. For example the following initialization will give you an error:
//ERROR: A lambda expression with a statement body cannot be converted to an expression tree
Expression<Action> ex = () =>
{
int a = 10;
int b = 21;
Console.WriteLine(a + b);
};
A way around this is to define a method which you can later on assign to the Expression object:
void Sum()
{
int a = 10;
int b = 21;
Console.WriteLine(a + b);
}
Valid assignment:
Expression<Action> ex = () => Sum();
Console.WriteLine(ex.ToString());
The above code prints () => Sum() on the console.
While reading a book named "Programming in C#", I've came across a syntax that I fail to understand :
public static void Main(string[] args)
{
new Thread( () =>
{
for(int x = 0; x < 10; x++)
{
_field++;
Console.WriteLine("Thread A : {0}", _field);
}
}).Start();
}
What does " () => " refers to, and what constructor is called ? I tried to google it but "() =>" is kinda hard to search on google.
This is a lambda expression, see here for the docs.
More specifically, it is an anonymous function. The Thread constructor requires a function that is called when the thread starts. Rather than creating a function for re-use (void ThreadFunc() { ... }), an anonymous function is declared in-line.
I do not know C# but this looks like an anonymous function. That is the Thread Object will run this function once start is called, on a seperate thread.
EDIT: its called anonymous because it has no name, also () => {} are 'arguments' => 'fun-body'
() => ... just means that it is the lambda expression that takes no parameters. It is same as the following
without parameter:
void MyWork() // This is your class constructor
{
for(int x = 0; x < 10; x++)
{
_field++;
Console.WriteLine("Thread A : {0}", _field);
}
}
new Thread(MyWork).Start();
With Parameter:
void MyWork(int _number) // This is your class constructor
{
for(int x = 0; x < _number; x++)
{
_field++;
Console.WriteLine("Thread A : {0}", _field);
}
}
new Thread(() => MyWork(10)).Start();
I'm just wondering if there is a C# equivilent for this python code.
I want to store the names of methods in some sort of collection and call them later on. I have searched, but I really don't know what to look for.
For example in python I could do:
def add_one(x):
return x + 1
def double_it(x):
return x*2
maths_rules = [add_one, double_it]
def do_maths(maths_rules, x):
for func in maths_rules:
x = func(x)
return x
print do_maths(maths_rules, 9)
# >>> 20
This is a silly example, but you should get the idea.
You are looking for delegates.
A delegate is a type that defines a method signature. When you instantiate a delegate, you can associate its instance with any method with a compatible signature. You can invoke
(or call) the method through the delegate instance.
Your example in C#, using the Func<T, TResult> Delegate:
int add_one(int x) { return x + 1; }
int double_it(int x) { return x * 2; }
var maths_rules = new List<Func<int,int>> { add_one, double_it };
int do_maths(IEnumerable<Func<int,int>> maths_rules, int x)
{
foreach (var func in maths_rules)
{
x = func(x);
}
return x;
}
Console.WriteLine(do_maths(maths_rules, 9));
// prints "20"
Yes, you can use delegates. For this one use Func<int, int>.
like:
int addone(int x)
{
return x + 1;
}
and in main:
Func<int, int> myFunc = new Func<int, int>(addone);
myFunc(5); // to use it, you can pass it as you like
example on your code:
static int add_one(int x)
{
return x + 1;
}
static int double_it(int x)
{
return x * 2;
}
static int do_maths(List<Func<int, int>> math_rules, int x)
{
foreach(var func in math_rules)
x = func(x);
return x;
}
static void Main(string[] Args)
{
List<Func<int, int>> math_rules = new List<Func<int, int>>();
math_rules.Add(new Func<int, int>(add_one));
math_rules.Add(new Func<int, int>(double_it));
Console.WriteLine(do_maths(math_rules, 9)); // 20
}
or use lambdas as suggested in comment:
static int do_maths(List<Func<int, int>> math_rules, int x)
{
foreach(var func in math_rules)
x = func(x);
return x;
}
static void Main(string[] Args)
{
List<Func<int, int>> math_rules = new List<Func<int, int>>();
math_rules.Add(new Func<int, int>((x) => (x + 1)));
math_rules.Add(new Func<int, int>((x) => (x * 2)));
Console.WriteLine(do_maths(math_rules, 9)); // 20
}
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
In the following program, DummyMethod always print 5. But if we use the commented code instead, we get different values (i.e. 1, 2, 3, 4). Can anybody please explain why this is happenning?
delegate int Methodx(object obj);
static int DummyMethod(int i)
{
Console.WriteLine("In DummyMethod method i = " + i);
return i + 10;
}
static void Main(string[] args)
{
List<Methodx> methods = new List<Methodx>();
for (int i = 0; i < 5; ++i)
{
methods.Add(delegate(object obj) { return DummyMethod(i); });
}
//methods.Add(delegate(object obj) { return DummyMethod(1); });
//methods.Add(delegate(object obj) { return DummyMethod(2); });
//methods.Add(delegate(object obj) { return DummyMethod(3); });
//methods.Add(delegate(object obj) { return DummyMethod(4); });
foreach (var method in methods)
{
int c = method(null);
Console.WriteLine("In main method c = " + c);
}
}
Also if the following code is used, I get the desired result.
for (int i = 0; i < 5; ++i)
{
int j = i;
methods.Add(delegate(object obj) { return DummyMethod(j); });
}
The problem is that you're capturing the same variable i in every delegate - which by the end of the loop just has the value 5.
Instead, you want each delegate to capture a different variable, which means declaring a new variable in the loop:
for (int i = 0; i < 5; ++i)
{
int localCopy = i;
methods.Add(delegate(object obj) { return DummyMethod(localCopy); });
}
This is a pretty common "gotcha" - you can read a bit more about captured variables and closures in my closures article.
This article will probably help you understand what is happening (i.e. what a closure is): http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
If you look at the code generated (using Reflector) you can see the difference:
private static void Method2()
{
List<Methodx> list = new List<Methodx>();
Methodx item = null;
<>c__DisplayClassa classa = new <>c__DisplayClassa();
classa.i = 0;
while (classa.i < 5)
{
if (item == null)
{
item = new Methodx(classa.<Method2>b__8);
}
list.Add(item);
classa.i++;
}
foreach (Methodx methodx2 in list)
{
Console.WriteLine("In main method c = " + methodx2(null));
}
}
When you use the initial code it creates a temporary class in the background, this class holds a reference to the "i" variable, so as per Jon's answer, you only see the final value of this.
private sealed class <>c__DisplayClassa
{
// Fields
public int i;
// Methods
public <>c__DisplayClassa();
public int <Method2>b__8(object obj);
}
I really recommend looking at the code in Reflector to see what's going on, its how I made sense of captured variables. Make sure you set the Optimization of the code to ".NET 1.0" in the Option menu, otherwise it'll hide all the behind scenes stuff.
I think it is because the variable i is put to the heap (it's a captured variable)
Take a look at this answer.