SoFunction
Updated on 2025-03-07

Detailed analysis of value passing and reference passing in C#

1. Pass parameters
Parameters can be passed either by values ​​or by reference. Passing parameters by reference allows function members (methods, properties, indexers, operators, and constructors) to change the value of the parameter and keep that change.

2. Pass the value type parameter
A value type variable contains its data directly, unlike a reference type variable, which contains a reference to its data. Therefore, passing a value type variable to a method means passing a copy of the variable to the method. Changes to parameters that occur within the method have no effect on the original data stored in the variable. If you want the called method to change the value of the parameter, you must pass the parameter by reference using the ref or out keywords. For simplicity, the following example uses ref.

1. Pass the value type through the value:

Copy the codeThe code is as follows:

class PassingValByVal
{
static void SquareIt(int x)
// The parameter x is passed by value.
// Changes to x will not affect the original value of x.
{
x *= x;
("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
("The value before calling the method: {0}", n);

SquareIt(n); // Passing the variable by value.
("The value after calling the method: {0}", n);
}
}


The variable n is a value type and contains its data (value is 5). When SquareIt is called, the content of n is copied into parameter x, and the parameter is squared within the method. But in Main, the value of n is the same before and after calling the SquareIt method. In fact, changes occurring within the method only affect the local variable x.

2. Pass the value type by reference
The following example is the same as the previous example except for passing parameters using the ref keyword. The value of the parameter changes after calling the method

Copy the codeThe code is as follows:

class PassingValByRef
{
static void SquareIt(ref int x)
// The parameter x is passed by reference.
// Changes to x will affect the original value of x.
{
x *= x;
("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
("The value before calling the method: {0}", n);

SquareIt(ref n); // Passing the variable by reference.
("The value after calling the method: {0}", n);
}
}


In this example, it is not a value of n, but a reference to n. The parameter x is not type int, it is a reference to int (in this case a reference to n). Therefore, when squared x within the method, the term referenced by x is actually squared: n.

3. Exchange value type
A common example of changing the value of the passed parameter is the Swap method, where the two variables x and y are passed, and then the method exchanges their contents. Parameters must be passed to the Swap method by reference; otherwise, what is processed within the method will be a local copy of the parameter. Here is an example of a Swap method that uses reference parameters:

Copy the codeThe code is as follows:

static void SwapByRef(ref int x, ref int y)
{
    int temp = x;
    x = y;
    y = temp;
}

3. Pass reference type parameters
A variable of a reference type does not directly contain its data; it contains a reference to its data. When passing parameters of reference type by values, it is possible to change the data pointed to by the reference, such as the value of a certain class of members. But the value of the reference itself cannot be changed; that is, the same reference cannot be used to allocate memory for the new class and keep it outside the block. To do this, the parameters should be passed using the ref or out keywords. For simplicity, the following example uses ref.

1. Pass the reference type by value
The following example demonstrates passing a parameter arr of reference type to the Change method through a value. Since this parameter is a reference to arr , it is possible to change the value of the array element. However, when trying to reassign the parameters to different memory locations, the operation is only valid within the method and does not affect the original variable arr.

Copy the codeThe code is as follows:

class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
("Inside the method, the first element is: {0}", pArray[0]);
}

static void Main()
{
int[] arr = {1, 4, 5};
("Inside Main, before calling the method, the first element is: {0}", arr [0]);

Change(arr);
("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}


In the previous example, the array arr is a reference type and is passed to the method without using the ref parameter. In this case, a copy of the reference pointing to arr is passed to the method. The output display method has the potential to change the contents of the array element, in which case, from 1 to 888. However, using the new operator within the Change method to allocate a new memory section will cause the variable pArray to refer to the new array. Therefore, any changes after this will not affect the original array arr (it was created inside Main). In fact, two arrays are created in this example, one in Main and one in Change method.

2. Pass the reference type by reference
This example is the same as in the previous example except for using the ref keyword in the method header and call. Any changes occurring within the method affect the original variables in the caller

Copy the codeThe code is as follows:

class PassingRefByRef
{
    static void Change(ref int[] pArray)
    {
        // Both of the following changes will affect the original variables:
        pArray[0] = 888;
        pArray = new int[5] {-3, -1, -2, -3, -4};
        ("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main()
    {
        int[] arr = {1, 4, 5};
        ("Inside Main, before calling the method, the first element is: {0}", arr[0]);

        Change(ref arr);
        ("Inside Main, after calling the method, the first element is: {0}", arr[0]);
    }
}


All changes occurring within the method affect the original array in Main. In fact, the original array is reassigned using the new operator. Therefore, after the Change method is called, any reference to arr will point to an array of five elements created in the Change method.

3. Swap two strings
Swap strings is a good example of passing reference type parameters through references. In this example, str1 and str2 are initialized in Main and passed to the SwapStrings method as parameters modified by the ref keyword. These two strings are exchanged within this method and within Main.

Copy the codeThe code is as follows:

class SwappingStrings
{
static void SwapStrings(ref string s1, ref string s2)
// The string parameter is passed by reference.
// Any changes on parameters will affect the original variables.
{
string temp = s1;
s1 = s2;
s2 = temp;
("Inside the method: {0} {1}", s1, s2);
}

static void Main()
{
string str1 = "John";
string str2 = "Smith";
("Inside Main, before swapping: {0} {1}", str1, str2);

SwapStrings(ref str1, ref str2); // Passing strings by reference
("Inside Main, after swapping: {0} {1}", str1, str2);
}
}


In this example, you need to pass parameters by reference to affect the variables in the calling program. If the ref keyword is removed from both the method header and the method call, no changes occur in the caller.

4. Data value transfer of reference type (replica transfer)
The class defaults to creating a shallow copy using the MemberwiseClone method, by creating a new object and then copying the non-static fields of the current object to the new object. If the field is of value type, bit-by-bit copying is performed on the field. If the field is a reference type, the referenced object is copied but not the referenced object; therefore, the original object and its copy refer to the same object. Deep copy means implementing the ICloneable interface. ICloneable can be used for deep copy and shallow copy. These are concepts, but we need to understand:

Copy the codeThe code is as follows:

   class ClassA : ICloneable
    {
        public string str;
        public SubClass subclass;
        public ClassA()
        {
            str = "classA str";
            subclass = new SubClass();
        }
//Deep copy, multi-layer cannot be fully implemented with MemberwiseClone()
        public object Clone()
        {
           // = (string)();
            // = (B)();
            var ne = new ClassA();
            = ;
= (SubClass)(); //If it is still not successful
            return ne;
           // return ();
        }
    }

    class SubClass : ICloneable
    {
        public string str;
        public SubClass()
        {
            = "subclass str";
        }
//Deep copy, because there is only one layer, you can use the MemberwiseClone() method
        public object Clone()
        {
            = (string)();
            return ();
        }