Call by reference not working as expected - c#

In the example of Microsoft's web there are below codes:
class TestRef
{
static void FillArray(ref int[] arr)
{
// Create the array on demand:
if (arr == null)
{
arr = new int[10];
}
// Fill the array:
arr[0] = 1111;
arr[4] = 5555;
}
}
If I delete the line of if (arr == null), the error output will be 0 0 0 0 0 not 1 2 3 4 5. Why?

This is because you are passing by ref this means that you are changing the pointer for that variable in the main method.
You are assigning it to a new int[] that is filled with the default value of int which is 0

its happening because when you put your code as it is it mean you are passing your intArray to the method but when you remove the lines as you have mentioned in this case new int[] is assigned to variable which will fill default 0 in your array.
this line arr = new int[10]; is assigning new int[] when you remove conditions.
As documented in the official site :-
A ref parameter of an array type may be altered as a result of the
call. For example, the array can be assigned the null value or can be
initialized to a different array.

Here in FillArray function you are passing the array by reference
but when you remove the if block
you re-initialize the array
when you initialize a value type array the elements take default value of the value typeIn this case it is int which have default value 0
You need to understand pass by value vs pass by reference in C#
http://www.programminginterviews.info/2011/05/pass-by-value-versus-reference-in-c.html
also value type vs ref type
http://www.albahari.com/valuevsreftypes.aspx

Related

What is the difference between myArray.GetValue(2) and myArray[2] in C#?

Is there any difference between using myArray.GetValue(2) and myArray[2]?
For example:
namespace ConsoleApplication16
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[] { 1, 2, 3, 4 };
Console.WriteLine(numbers.GetValue(3));
Console.WriteLine(numbers[3]);
Console.ReadLine();
}
}
}
GetValue will return type object while using the index will return the type specific with the array.
You can see in this fiddle (code below) that the variable val1 can have a string stored in it, but val2 can only be used as an integer.
public static void Main()
{
int[] numbers = new int[]{1, 2, 3, 4};
var val1 = numbers.GetValue(3);
var type = val1.GetType();
var val2 = numbers[3];
Console.WriteLine(type.ToString());
val1 = "hello";
type = val1.GetType();
Console.WriteLine(type.ToString());
}
This will result in boxing and unboxing, which won't have an effect on a small code snippet, but if used in large scale it could potentially affect performance.
In your code, there isn't a difference. The primary difference, inside an array when you call Array.GetValue(1) you're receiving the value of that index. You can't specifically set the value of the array though.
If you were to do Array[1] = "..."; you've modified the array. But you can also still attain the value, though it may not be as expressive as above. So you can get or set a value with this approach.
The number of elements in indices must equal the number of dimensions
in the Array. All elements in the indices array must collectively
specify the position of the desired element in the multidimensional
Array. The GetLowerBound and GetUpperBound methods can determine
whether any of the indexes is out of bounds. This method is an O(1)
operation.
Both are susceptible do the above though.
numbers.GetValue(3) returns an object and therefor the overload Console.WriteLine(object value) that takes an object parameter is called.
numbers[3] is of type int and then Console.WriteLine(int value) that takes an int as parameter is called.
So you end up calling different methods.
When you are using Array class(with uppercase) there are not indexers. So the way you can get and set elements on it is using GetValue() or SetValue()
See this link : Using an array's SetValue method vs. the [] indexers
In use-ability there isn't a difference except for setting values. The difference however seems to be in how it gets the value.
Array's .GetValue gives me this, it returns an object.
Either approach takes under 1ms so there isn't a substantial speed difference either.

How to resize an array of int larger and have the default values null and not 0

From my understanding arrays are always nullable. However when I want to resize an array to a larger size I would expect it to return nulls in the new elements. However it returns 0;
Example:
int[] myArray = { 1, 2, 3 };
Array.Resize(ref myArray, 100);
int? shouldBeNull = myArray[3];
How do I get the myArray[3] to return null and not 0 like it is currently?
From my understanding arrays are always nullable
They are, in the sense that int[] someArray = null compiles.
An array of a non-nullable type still can't contain null values though. It will contain default(T), which is 0 in the case of int.
It seems you're looking for an array of nullable ints, or int?[].

C# passing int[] (array) with and without ref [duplicate]

This question already has answers here:
Why would ref be used for array parameters in C#?
(2 answers)
What is the use of "ref" for reference-type variables in C#?
(10 answers)
Closed 7 years ago.
I am slightly confused about this, as I have read that an int[] array, although int is a primitive type, since it's an array, it's a reference type variable.
What is the different then between a method such as:
public static void ChangeSomething(ref int[] array)
{
array[0] = 100;
}
and
public static void ChangeSomething(int[] array)
{
array[0] = 100;
}
When the array is modified, I can see the new value of 100 at index 0 for both of these calls.
Is there something different that happens under the covers which makes one better than another? Does the VS IDE allow both simply because perhaps the "ref" keyword clarifies the intention?
The difference is that you can assign the original variable directly in the method. If you change your method to the this:
public static void ChangeSomething(ref int[] array)
{
array = new int[2];
}
And call it like this:
var myArray = new int[10];
ChangeSomething(ref myArray);
Console.WriteLine(array.Length);
You will see that myArray only have a length of 2 after the call. Without the ref keyword you can only change the content of the array, since the array's reference is copied into the method.
If you modify the items of the array, there is no difference.
But if you redefined the array itself with larger array, there is the difference:
public static void ChangeSomething(ref int[] array)
{
array = new int[100]; //you are changing the variable of caller
}
and
public static void ChangeSomething(int[] array)
{
array = new int[100]; //you are changing local copy of array variable, the caller array remains same.
}

Passing Arrays by Value and by Reference

These are example from a c# book that I am reading just having a little trouble grasping what this example is actually doing would like an explanation to help me further understand what is happening here.
//creates and initialzes firstArray
int[] firstArray = { 1, 2, 3 };
//Copy the reference in variable firstArray and assign it to firstarraycopy
int[] firstArrayCopy = firstArray;
Console.WriteLine("Test passing firstArray reference by value");
Console.Write("\nContents of firstArray " +
"Before calling FirstDouble:\n\t");
//display contents of firstArray with forloop using counter
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
//pass variable firstArray by value to FirstDouble
FirstDouble(firstArray);
Console.Write("\n\nContents of firstArray after " +
"calling FirstDouble\n\t");
//display contents of firstArray
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
// test whether reference was changed by FirstDouble
if (firstArray == firstArrayCopy)
Console.WriteLine(
"\n\nThe references refer to the same array");
else
Console.WriteLine(
"\n\nThe references refer to different arrays");
//method firstdouble with a parameter array
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
Basically there is the code what I would like to know is that the book is saying if the array is passed by value than the original caller does not get modified by the method(from what i understand). So towards the end of method FirstDouble they try and assign local variable array to a new set of elements which fails and the new values of the original caller when displayed are 2,4,6.
Now my confusion is how did the for loop in method FirstDouble modify the original caller firstArray to 2,4,6 if it was passed by value. I thought the value should remain 1,2,3.
Thanks in advance
The key to understanding this is to know the difference between a value type and a reference type.
For example, consider a typical value type, int.
int a = 1;
int b = a;
a++;
After this code has executed, a has the value 2, and b has the value 1. Because int is a value type, b = a takes a copy of the value of a.
Now consider a class:
MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;
Because classes are reference types, b = a merely assigns the reference rather than the value. So b and a both refer to the same object. Hence, after a.MyProperty = 2 executes, b.MyProperty == 2 since a and b refer to the same object.
Considering the code in your question, an array is a reference type and so for this function:
public static void FirstDouble(int[] array)
the variable array is actually a reference, because int[] is a reference type. So array is a reference that is passed by value.
Thus, modifications made to array inside the function are actually applied to the int[] object to which array refers. And so those modifications are visible to all references that refer to that same object. And that includes the reference that the caller holds.
Now, if we look at the implementation of this function:
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
}
there is one further complication. The for loop simply doubles each element of the int[] that is passed to the function. That's the modification that the caller sees. The second part is the assignment of a new int[] object to the local variable array. This is not visible to the caller because all it does is to change the target of the reference array. And since the reference array is passed by value, the caller does not see that new object.
If the function had been declared like this:
public static void FirstDouble(ref int[] array)
then the reference array would have been passed by reference and the caller would see the newly created object { 11, 12, 13 } when the function returned.
What a confusing use of terms!
To clarify,
for a method foo(int[] myArray), "passing a reference (object) by value" actually means "passing a copy of the object's address (reference)". The value of this 'copy', ie. myArray, is initially the Address (reference) of the original object, meaning it points to the original object. Hence, any change to the content pointed to by myArray will affect the content of the original object.
However, since the 'value' of myArray itself is a copy, any change to this 'value' will not affect the original object nor its contents.
for a method foo(ref int[] refArray), "passing a reference (object) by reference" means "passing the object's address (reference) itself (not a copy)". That means refArray is actually the original address of the object itself, not a copy. Hence, any change to the 'value' of refArray, or the content pointed to by refArray is a direct change on the original object itself.
All method parameters are passed by value unless you specifically see ref or out.
Arrays are reference types. This means that you're passing a reference by value.
The reference itself is only changed when you assign a new array to it, which is why those assignments aren't reflected in the caller. When you de-reference the object (the array here) and modify the underlying value you aren't changing the variable, just what it points to. This change will be "seen" by the caller as well, even though the variable (i.e. what it points to) remains constant.
idea for you all there with knowledge of .net open sources to implement the logics;
//Sample Code, Illustration;
Method1(params dynamic[] var1) {
var1[0]=new dynamic[3] { 1,2,3 }
}
the var1 is not specified or cannot be ref ?
a usage scenario would be ...
//Sample Code, Illustration;
dynamic[] test = new dynamic[];
Method1( ref test,x,x,x,x );
System.Windows.MessageBox.Show( test[2].ToString() );
to indicate ref only when, not being a parameter specific;
and a ref to array items;
//result is IndexOutOfBounds;
this is only a illustrationm it can be done by returning a array and use like:
test = Method1( test,... );
instead of :
Method1( ref test,x,x,..., ref test[x], ref test2, ... );

Casting system.array to object in c#

my function has the following signature
function myfunction(ref object)
I use it as such
Array arr = Array.CreateInstance(System.Type.GetType("System.String"), 2);
arr.SetValue("1", 0);
myfunction( ref arr);
And I am getting
"cannot convert from 'ref System.Array' to 'ref object'"
I was under the impression that System.Array is object ...so why am I getting this error? Is object different from Object?
The problem you're having is that while an array is an object, an object is not an array, so in your function, if your array could be passed in as a ref object, the array could be assigned anything that is an object.
Edit:
To fix this problem declare a ref variable to use in place of the array variable:
Array arr = Array.CreateInstance(System.Type.GetType("System.String"), 2);
arr.SetValue("1", 0);
object referenceObject = arr;
myfunction( ref referenceObject );
Think of 'ref object' as "I take a reference to a variable that can store an Object". Suppose that 'myfunction' tried to store an 'int' to the variable you passed? This would fail at runtime, which is undesirable.
On a side note, you can use typeof(string) in place of calling GetType("System.String"). You can also just say:
Object arr = new string[2];
To access the array first, you can do this:
string[] arr = new string[2];
arr[0] = "1";
object arrObj = arr;
myfunction(ref arrObj);
I would double check that you're using the method myfunction correctly; it's a rather unusual parameter type for taking an initialized array.
Declare the variable as object and not as array.
To populate the array with values you should keep your array variable and declare another one to give it to the method.
Array myArray = ....;
Object myObject = myArray;
myFunction(ref myObject);
// Update the original reference
myArray = myObject as Array;

Categories

Resources