Pass on variable to set in C# - c#

I want a pass several variables to a function to and set them to something else instead of reading from them. I am planning to use this in a scenario where i can create a object, and add it to a execution queue. Would a pointer be right for this?
I am aware my question has a poor explanation, but I don't know a better way to explain it.

It sounds like you probably want a ref or out parameter. For example:
public static void SetVariables(out int x, ref int y)
{
// Can't *read* from x at all before it's set
x = 10;
// Can read and write y
y++;
}
public static void Foo()
{
int setOnly;
int increment = 5;
SetVariables(out setOnly, ref increment);
Console.WriteLine("{0} {1}", setOnly, increment); // 10 6
}
See my parameter passing article for more information.

Are these variables reference types or value types? If they are reference types then you can pass them into your function as per normal and then mutate its properties from there. If they are value types then you must use the ref keyboard.

Related

Unnecessary assignment of a value to 'player"

I am having a problem assigning values in my function. Here is my code
//Player cents
private int add_cents = 3;
public int player_1, enemy_1, enemy_2, enemy_3;
public void players_ready()
{
add_cents_player(player_1, add_cents);
}
public void add_cents_player(int player, int cent_v)
{
player = player + cent_v;
}
I want to be able to call this function and input whoever is the active player (player) and increase their value by (cent_v). However, player = player + cent_v; is saying "Unnecessary assignment of a value to 'player" and I don't understand why. It wouldn't be possible to hard code, as it is dependant on what who is the active player.
One option is to change the method return type:
private int add_cents = 3;
public int player_1, enemy_1, enemy_2, enemy_3;
public void players_ready()
{
player_1 = add_cents_player(player_1, add_cents);
}
public int add_cents_player(int player, int cent_v)
{
return player + cent_v;
}
int is a value type. It is passed by value meaning the player will actually be a copy of player_1. If you then change the player inside your method this doesn't affect in any way the player_1 since it is no reference and no relationship between them.
It looks like what you wanted to do would be using ref in order to "force" the value to be passed by reference
public void players_ready()
{
add_cents_player(ref player_1, add_cents);
}
public void add_cents_player(ref int player, int cent_v)
{
player += cent_v;
}
thus that after calling players_ready the value player_1 is actually increased
There are 2 ways to pass a variable to a function. 1 is by reference, meaning you pass a reference to a variable into the function. This is what happens with variables of type object - not the whole object's memory is copied and supplied to the function, but only an address to the piece of memory where that object resides.
For int, float etc. this is different. The values are passed by value.
Also see the relevant msdn docs.
There is a fundamental difference between the two options: reference types are passed by reference and can be altered and the original object also gets altered. E.g. this works:
class MySimpleObject // an object is a reference type
{
public int someValueType; // int is a value type
}
...
var x = new MySimpleObject();
myFunc(x); // increment x.someValueType by 5
This does not count for objects passed by value, which is what happens with int, as its a value type. Therefore your function does nothing, because its only manpulating the local value, the reference is not passed.
var player_1 = 5;
add_cents_player(player_1, 15);
// Player_1 is still 5
add_cents_player(player_1, 15);
// Player_1 is still 5
...
And thats what the compiler is complaining about; you're adding a value to the local parameter in the function. But since you don't return this, or read the value at some point the compiler is like 'hey this code does nothing, and therefore its better to remove it.

Using out keyword in c#

can anyone suggest me the exact use of out keyword as a paramter, and how its connected for returning multiple values from the function, as in this POST, i am confused with out variable with normal variable. can anyone help me for this.
This is frequently confusing, and I think the MSDN documentation actually is a bit "clear only if already known". That is, it is correct, but it really only makes sense if you already understand the concept.
Here's how I think of it.
A regular parameter makes a copy of the value of the argument. When you say:
static int M(int z) { z = z + 1; return z; }
...
int x = 123;
int y = M(x);
That is just like you said:
int x = 123;
int z = x; // make a copy of x
z = z + 1;
int y = z;
A ref or out parameter make an alias for an existing variable. When you say
static void N(ref int q) { q = q + 1; }
...
int x = 123;
N(x);
That is the same as saying:
int x = 123;
// MAGIC: q is now an another name for variable x
q = q + 1;
q and x are two different names that refer to the same variable. Incrementing q also increments x because they are the same. z and x in the previous example are two different names that refer to two different variables. Incrementing z does not change x.
Summing up: "out" and "ref" just mean "do not make a new variable; rather, temporarily make a second name for an existing variable".
Is that now clear?
UPDATE: I did not say what the difference between "out" and "ref" is. The difference is simple. On the "caller" side, a "ref" must be a definitely assigned variable before the method is called. An "out" need not be. On the "callee" side, a "ref" may be read before it is written to, but an "out" must be written to before it is read. Also, an "out" must be written to before control leaves the method normally.
MSDN documentation already does a great job explaining this:
The out keyword causes arguments to be passed by reference. This is
similar to the ref keyword, except that ref requires that the variable
be initialized before being passed. To use an out parameter, both the
method definition and the calling method must explicitly use the out
keyword. For example:
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
It's very frequently used in a pattern that "tries" to get a value, something like:
int result;
if(Int32.TryParse("123", out result))
{
Console.WriteLine(result + 1);
}
out keyword should be used when you want to:
a) Allow your function to modify specific variable from calling code stack AND
b) enforce setting this variable value inside your function
MSDN is always a good place to start
In most languages c# included you can pass values in 2 ways, by value, by reference.
by value gives the method a copy of your data, so changing the data wont have any effect on the original data
by reference essentially gives the method the memory address of your data, so if the method modifies the data, it changes the original.
Out is a special type of ref, in that you do not need to initialise the variable before you call the method, it can be called with null being passed in. and it MUST be set by the method.
Another way you can think of it (from the outside code's point of view) is:
val = read only
ref = read/write
out = write only.
http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx
out keyword is good if you want to return multiple values of pre-defined types (for example an int, a List<string> and a DateTime), and you don't want to create a new class just for this purpose.
Ok,
let look at the usual pattern for this kind of function - the TrySomething.
Suppose you have a function that might succeed giving you an value or not but you don't won't to use an exception for this because you don't want the overhead or it's a common trait.
Then you normaly return true if the method suceeded and false if not. But where would you put your outputvalue to?
One possible answer is using an out parameter like this:
bool TrySomething(MyInputType input, out MyOutputType output)
{
output = default(MyOutputType);
/* ... Try getting the answer ... */
if (!successful)
return false;
output = successfulOutput;
return true;
}
Remark:
Or you might consider using a Tuple<bool,MyOutputType> and indeed F# interpretes the pattern above as resulting in such a tuple by itself.

Can I use a reference inside a C# function like C++?

In C++ I can do this:
int flag=0,int1=0,int2=1;
int &iRef = (flag==0?int1:int2);
iRef +=1;
with the effect that int1 gets incremented.
I have to modify some older c# code and it would be really helpful if I could do something similar, but I'm thinking ... maybe not. Anybody?
UPDATE: The feature discussed below was finally added in C# 7.
The feature you want - to make managed local variable aliases is not supported in C#. You can do it with formal parameters - you can make a formal parameter that is an alias of any variable - but you cannot make a local which is an alias of any variable.
However, there is no technical difficulty stopping us from doing so; the CLR type system supports "ref local variables". (It also supports ref return types but does not support ref fields.)
A few years back I actually wrote a prototype version of C# which supported ref locals and ref return types, and it worked very nicely, so we have empirical evidence that we can do so successfully. However, it is highly unlikely that this feature will be added to C# any time soon, if ever. See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.
I note that if I were you, I would avoid this in any language. Writing programs in which two variables share the same storage makes for code that is hard to read, hard to understand, hard to modify and hard to maintain.
See also the related question: Why doesn't C# support the return of references?
You can do it - or at least something very similar to what you want - but it's probably best to find another approach. For example, you can wrap the integers inside a simple reference type.
If you still want to do it, see the Ref<T> class posted by Eric Lippert here:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
public class Program
{
public static void Main()
{
int flag=0,int1=0,int2=1;
Ref<int> iRef = (flag == 0 ?
new Ref<int>(() => int1, z => { int1 = z; }) :
new Ref<int>(() => int2, z => { int2 = z; }));
iRef.Value += 1;
Console.WriteLine(int1);
}
}
Output:
1
If all you need is to modify a value type within a function, then pass the parameter with the ref keyword.
int i = 0;
void increment(ref int integer)
{
integer++;
}
increment(ref i);
Yes you can do that with C# 7.0. It has support for returning references and storing references. See my answer here.
Fraid not. You could do it with unsafe code and pointers like so:
int flag=0,int1=0,int2=1;
unsafe
{
int *iRef = (flag==0? &int1:&int2);
*iRef +=1;
}
(not saying that's a good idea or anything :))
There is no direct equivelent in C#. There are a couple of options -
You can use unsafe code and pointers as suggested by dkackman.
Another alternative is to use a reference type (class) which holds the value. For exmaple:
// Using something like
public class Wrapped<T> {
public Wrapped(T initial) {
this.Value = initial;
}
public T Value { get; set; }
}
// You can do:
bool flag=false;
var int1 = new Wrapped<int>(0);
var int2 = new Wrapped<int>(1);
Wrapped<int> iRef = flag ? int2 : int1;
iRef.Value = iRef.Value + 1;
Since you're working with references to a class, the assignment to iRef copies the reference, and the above works...
You could use an Action delegate like this:
int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();

Changing an Actual Parameter in C#

In C++, I have a function:
void MyFunction(int p)
{
p=5;
}
Assume, I have:
int x = 10;
MyFunction(x); // x = 10
MyFunction(&x); // x = 5
How to archieve this in C# with condition: I create only one MyFunction.
Your C++ function doesn't work the way you think it does. In fact, your code will not compile.
In C#, you would use the ref or out keywords:
void MyFunction1(out int p)
{
p = 5;
}
void MyFunction2(ref int p)
{
p = p + 1;
}
int x;
MyFunction1(out x); // x == 5
MyFunction2(ref x); // x == 6
In C# you would need to declare the method with a ref parameter, like this:
void MyFunction(ref int p)
{
p=5;
}
If you then call it as MyFunction(ref x) the value of x in the caller will be modified. If you don't want it to be modified simply copy it to a dummy variable. You could create an overload of MyFunction that does this internally:
void MyFunction(int p)
{
MyFunction(ref p);
}
It would technically not be "one function", as you want, but the code wouldn't be duplicated and to any human reading your code it would appear as one - but to the compiler it's two. You would call them like this:
int x = 10;
MyFunction(x); // x = 10
MyFunction(ref x); // x = 5
C# does not have the equivalent functionality. If you declare the method to have a ref parameter, then you must also specify that the parameter is ref type when you call the method.
You need to pass the parameter as reference. If you don't specify it, it automatically creates a copy to work inside the parameter instead of using the same reference.
How to do that? Just specify with the 'ref' word in method declaration:
void MyFunction(ref int p)
{
p=5;
}
int x = 10;
MyFunction(ref x); // x = 5
The point is that a lot of people think that Reference types are passed by reference and Value types are passed By Value. This is the case from a user's perspective, internally both Reference and Value types are passed By Value only.
When a Reference type is passed as a parameter, its value, which is a reference to the actual object is passed. In case of Value types, their value is the value itself (e.g. 5).
StringBuilder sb = new StringBuilder();
SetNull(sb);
SetNull(ref sb);
if SetNull(...) sets the parameter to null, then the second call will set the passed in StringBuilder parameter to null.

How to downcast a ref variable within the method

I need to downcast a long to an int in a method where the long is passed as a ref variable:
public void Foo(ref long l)
{
// need to consume l as an int
}
How can I easily do this?
You can't. However, any value you want to put into a ref int can be put into a ref long anyway - you've just got to worry about the initial value, and what you want to do if it's outside the range of int.
How many places do you need to write to the ref parameter or read it within your code? If it's only in one or two places, you should be okay just to cast appropriately at the right times. Otherwise, you might want to introduce a new method:
public void Foo(ref int x)
{
// Here's the body I *really* want
}
public void Foo(ref long x)
{
// But I'm forced to use this signature for whatever
// reasons. Oh well. This hack isn't an *exact* mimic
// of ref behaviour, but it's close.
// TODO: Decide an overflow policy
int tmp = (int) x;
Foo(ref tmp);
x = tmp;
}
The reason I say in the comments that it's not an exact mimic for the behaviour is that normally changes to the original ref parameter are visible even before the method returns, but now they'll only be visible at the very end. Also, if the method throws an exception, the value won't have been changed. The latter could be fixed with try/finally, but that's a bit clunky. In fact, if you want the try/finally behaviour you can do it all in a single method easily:
public void Foo(ref long x)
{
int y = (int) x;
try
{
// Main body of code
}
finally
{
x = y;
}
}
You don't. You can't take your reference and point it to a different type. How would the code calling your method know that it's changed?
If you just want to work with the value as an int, then you could do something like this:
private void Process(ref long l)
{
int i = (int)l;
// do whatever
}
You're a little light on the details, but if you're talking about this scenario:
public void Something(ref long something)
{
// code
}
int foo;
Something(ref foo);
try this:
long foo;
Something(ref foo);
int bar = (int) foo;
You can't safely cast a long to an int regardless of whether it's nullable or not as theres a chance it will overflow.
try this
if (!blah.HasValue)
blah = long.MaxValue;
int x = (int)blah.Value;
Console.WriteLine(x); //Not What you expect
You cannot directly cast this. The best option would be to cast it to a local, then assign it at the end of your method.
void Method(ref long myValue)
{
int tempValue = (int)myValue;
// change tempValue
myValue = tempValue;
}

Categories

Resources