Given the code below:
class Sample
{
public static void Run()
{
int i = 1;
Action<int> change = Increment();
for (int x = 0; x < 5; x++ )
{
change(i);
Console.WriteLine("value=" + i.ToString());
}
}
public static Action<int> Increment()
{
return delegate(int i) { i++; };
}
}
I get the answer:
value=1
value=1
value=1
value=1
value=1
value=1
Instead of 1, 2, 3 ... 6.
This is from an article on the net with links to clues but I can't work out why this is. Anyone have any ideas?
Your parameter is being passed by value.
Writing i++ will change the value of i to a different int value (unlike a mutable type).
When you write i++ inside the delegate, you're changing the parameter to be equal to a different int value. However, this does not affect the local variable whose value was copied to the parameter.
To solve this, you need to make a delegate with a ref parameter. ref parameters are passed by reference. Therefore, when you change a ref int parameter to a different int value, you'll also change the local variable or field whose reference was passed as the parameter.
For more information, see here.
Since the Action delegates do not take ref parameters, you'll need to make your own delegate type, like this:
delegate void RefAction<T>(ref T param);
The datatype int is a primitive data type and hence a value-type as opposed to a reference type. This means that when you pass variable i to a function it isn't the actual variable that has been passed but instead a copy of the value. And therefore when the parameter is changed inside the function it is the local copy that has been changed and no the original variable.
If you are certain you want the function to be able to modify the value of the original variable, then you should add the ref keyword to the function parameter signature to tell the compiler that you want to pass the variable as a reference.
public void ChangeOriginal(ref int something)
{ something = something + 1;}
public void ChangeLocalCopy(int something)
{something = something + 1;}
I suggest you read up upon the stack vs the heap (value-type vs reference-type) since it's a very fundamental subject when programming.
the Action returns nothing. Its only incrementing the value passed in - not the reference to the orginal (as Slaks says). You can use a Func to do in this way.
class Sample
{
public static void Run()
{
int i = 1;
Func<int, int> change = Increment();
for (int x = 0; x < 5; x++ )
{
i = change(i);
Console.WriteLine("value=" + i.ToString());
}
}
public static Func<int, int> Increment()
{
return delegate(int i) { return ++i; };
}
}
Related
I want to ask something about ref modifier.
What I know and understand:
With method that use ref modifier, there will be no copy of data as with passing by value, but parameter will have directly access to argument value. Basically said, all you done in method’s scope will act same as if you would done it with argument (passed variable) in caller’s scope.
and I want to ask what is exactly stored in parameter with ref modifier:
When I pass argument to method with ref modifier, will parameter contain reference to value of argument? or is it something else?
Thank you for your answers
When you have a parameter with the ref attribute, it passes the argument by reference and not value. That means a new copy of the variable is not being made, rather a pointer to the original is being used within your function.
public void Foo()
{
var x = 0;
Bar(x); // x still equals 0
Bar(ref x); // x now equals 1
}
public void Bar(ref int x)
{
x = 1;
}
public void Bar(int x)
{
x = 1;
}
Let's say we have this method:
public void DoSomething(int number)
{
number = 20;
}
And we use it:
var number = 10;
DoSomething(number);
Console.WriteLine("Our number is: {0}", number);
The output would be Our number is: 10. Our number does not become 20.
That's because we're passing by value, so we're basically taking a copy of number before we change it.
However, if we pass by reference instead:
public void DoSomething(ref int number)
{
number = 20;
}
And then use our method:
var number = 10;
DoSomething(ref number);
Console.WriteLine("Our number is: {0}", number);
The output then becomes Our number is: 20
I am trying to pass an argument to a method, and then use that argument as a array extension method, but I am struggling. My code is:
//create method
public static void BankChoice(string SearchItem)
{
//declare variables
double tempMin = 0;
int minIndex = 0;
//set a temporary double as the first index of array
tempMin = Program.array_SH1[0].SearchItem;
//start loop to go through whole array
for (int y = 0; y <= array_SH1.Length; y++)
{
//if the temp double is bigger than the array item,
//make array item temp double
if (tempMin > array_SH1[y].SearchItem)
{
tempMin = array_SH1[y].SearchItem;
minIndex = y;
}
}
}
I would then call the code as:
BankChoice("OpenPrice")
However this doesn't work. The compiler won't accept the string as the array extension and it just throws and error.
Is there anyway to fix this without having to do it longhand, and create a method for all variations of SearchItem
Thanks
What you can do is to supply a delegate:
public static void BankChoice(Func<ArrayValueType, double> searchBy)
{
//...
// use the delegate to evaluate the result for each time you need to get the value from an item in your array.
tempMin = searchBy(Program.array_SH1[0]);
//...
}
Where ArrayValueType is the type of object in your array. Then you call it with
BankChoice(x => x.OpenPrice);
This will allow you to specify a property to search on, and it will be done in a type safe manner. The only restriction at the moment is that the property is convertible to a double. It's possible to get around that for properties of a generic type, and there are various ways to do that depending on what your needs are.
I am using a console app using C# that has a method that calls another method and passes an out parameter
public void method1()
{
int trycount = 0;
....
foreach (var gtin in gtins)
{
method2(gtin, out trycount);
}
if (trycount > 5)
{...}
}
public void method2 (string gtin, out int trycount)
{
//gives me a compilation error if i don't assign
//trycount=0;
......
trycount++;
}
I don't want to override the trycount variable = 0 because after the second time the foreach gets executed in the method1 the trycount has a value. I want to pass the variable back so after the foreach I can check the parameter's value.
I know i can do something like return trycount = method2(gtin, trycount) but I wanted to try doing with an out parameter if possible. thanks
It sounds like you want a ref parameter instead of an out parameter. Basically out is like having an extra return value - it doesn't logically have a value initially (it's not definitely assigned, and has to be definitely assigned before the method exits normally).
That's also why you don't have to have a definitely assigned variable to use it as an argument:
int x;
// x isn't definitely assigned here
MethodWithOut(out x);
// Now it is
Console.WriteLine(x);
Logically, x doesn't have any value when you call MethodWithOut, so if the method could use the value, what value would you expect it to get?
Compare this with a ref parameter, which is effective "in and out" - the variable you use for the argument has to be definitely assigned before the call, the parameter is initially definitely assigned, so you can read from it, and changes made to it within the method are visible to the caller.
For more details on C# parameter passing, see my article on the topic.
(As an aside, I'd strongly recommend that you get in the habit of following .NET naming conventions even in demo code. It reduces the cognitive load of reading it.)
A better option would be to use a ref instead of an out. you would set it up like this:
public void method1()
{
int trycount = 0;
....
foreach (var gtin in gtins)
{
method2(gtin, ref trycount);
}
if (trycount > 5)
{...}
}
public void method2 (string gtin, ref int trycount)
{
......
trycount++; // this will modify the variable declared earlier
}
I have defined a function where one of the parameters is out. Here, when the function call is made, I pass either a an initialized or an uninitialized argument.
Now, in the case of an initialized argument, how do I make the callee not change the value of the out parameter?
I cant use a ref here because sometimes I do send an uninitialized argument.
Ex:
void fun1()
{
int x = 3;
fun2 (out x);
int y;
fun2(out y);
}
void fun2(out int x)
{
...
}
Here, I dont want the x to lose the value 3 once control goes to fun2.
From out C# - MSDN
Although variables passed as out arguments do not have to be initialized before being passed, the called method is required to assign a value before the method returns.
Since a value must be assigned to the parameter with out, you can't save the value in function. It would be better if you make a copy of the variable before calling the function. like:
int x = 1;
int backupX = x;
fun2(out x);
Maybe I get all wrong, but this sounds like you just want to define a method like this
void caller(){
int x=5;
int y = doSomething(x);
}
int doSomething(int x){
return x+1;
}
or in case you want a null state use:
void caller(){
int? x=5;
int y = doSomething(x);
}
int doSomething(int? x){
if (x == null)
return x;
return x+1;
}
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Why use ref keyword when passing an Object?
When to pass ref keyword in
What is the correct usage of the 'ref' keyword in C#. I believe there has been plenty of discussion threads on this, but what is not clear to me is:
Is the ref keyword required if you are passing in a reference object? I mean when you create an object in the heap, is it not always passed by reference. Does this have to be explicitly marked as a ref?
Using ref means that the reference is passed to the function.
The default behaviour is that the function receives a new reference to the same object. This means if you change the value of the reference (e.g. set it to a new object) then you are no longer pointing to the original, source object. When you pass using ref then changing the value of the reference changes the source reference - because they are the same thing.
Consider this:
public class Thing
{
public string Property {get;set;}
}
public static void Go(Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}
public static void Go(ref Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}
Then if you run
var g = new Thing();
// this will not alter g
Go(g);
// this *will* alter g
Go(ref g);
There is a lot of confusing misinformation in the answers here. The easiest way to understand this is to abandon the idea that "ref" means "by reference". A better way to think about it is that "ref" means "I want this formal parameter on the callee side to be an alias for a particular variable on the caller side".
When you say
void M(ref int y) { y = 123; }
...
int x = 456;
M(ref x);
that is saying "during the call to M, the formal parameter y on the callee side is another name for the variable x on the caller side". Assigning 123 to y is exactly the same as assigning 123 to x because they are the same variable, a variable with two names.
That's all. Don't think about reference types or value types or whatever, don't think about passing by reference or passing by value. All "ref" means is "temporarily make a second name for this variable".
I believe the ref keyword indicates that you are passing the object by reference, not by value. For example:
void myfunction(ref object a) {
a = new Something();
}
would change the value of a in the calling function
However,
void myfunction(object a) {
a = new Something();
}
would change the value of a locally, but not in the calling function. You can still change PROPERTIES of the item, but you cannot set the value of the item itself. For example;
a.someproperty = value;
would work in both cases.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace InOutRef
{
static class InOutRef
{
public static void In(int i)
{
Console.WriteLine(i);
i=100;
Console.WriteLine(i);
}
public static void Ref(ref int i)
{
Console.WriteLine(i);
i=200;
Console.WriteLine(i);
}
public static void Out(out int i)
{
//Console.WriteLine(i); //Error Unsigned Ref
i=300;
Console.WriteLine(i);
}
}
class Program
{
static void Main(string[] args)
{
int i = 1;
InOutRef.In(i); //passed by value (in only)
Debug.Assert(i==1);
InOutRef.Ref(ref i); //passed by ref (in or out)
Debug.Assert(i == 200);
InOutRef.Out(out i); //passed by as out ref (out only)
Debug.Assert(i == 300);
}
}
}
I can't be any more literal on my answer. The code will not remember reference chanages such as the classic Java swap question when using in. However, when using ref, it will be similar to VB.NET as it will remember the changes in and out. If you use the out parameter it means that it must be declared before you return (this is enforced by the compiler).
Output:
1 //1 from main
100 //100 from in
1 //1 is NOT remembered from In
200 //200 from ref
//should be 200 here but out enforces out param (not printed because commented out)
300 //300 is out only
Press any key to continue . . .