C# Passing by Value vs Passing by Reference
Tags: csharp, methods
Published: 2024-06-12 19:23:21


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3my9j5vii7ai77ktq3yu.png)

Have you ever wondered why changes inside a function sometimes affect your variables, and other times do not? offers two ways to pass data: by value (copy) or reference (pointer). This article breaks down the distinction between the two, and how each works. Let's learn to control our data flow and write rock-solid code!

## Understanding Value Types and Reference Types

The two main categories Of types are reference and value A value type variable holds an instance Of the type. A reference variable, on the other hand, contains a reference to an instance of the type. Value types are allocated on the stack and deallocated when the stack unwinds or their containing type gets deallocated. This contrasts reference types, which are allocated on the heap and garbage-collected. Value-type variables can be used as fields in reference-type objects. To dive into how .NET treats value and reference types check out [Choosing Between Class and Struct](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct)

Value types are the built-in types in C# like `int`, `long`, `double`, etc., or user-defined types like `struct` types. on the other hand, reference types are like arrays, classes, and so on.

Let's define some value types variables:

```csharp
int discountRate = 50;
double productAPrice = 60;
```

Now let's define some reference type variables:

First, let's define our **Product** class to hold our ProductId, and Price.

```csharp
public class Product
{
    public int ProductId { get; set; }
    public int Price { get; set; }
}
```

Then let's use our class to create a new object from it like:

```csharp
var product = new Product
{
    ProductId = 1,
    Price = 60
};
```

## Passing by Value

By default, when we pass a parameter into our method we pass it by value, which means it copies the object value to our method. Therefore, any modifications in our method do not affect the original variable. This applies only to the built-in or struct types.

Let's update the price from our `UpdatePriceByPercent` method:

```csharp
UpdatePriceByPercent(productAPrice, discountRate);

public static void UpdatePriceByPercent(double price, int discountRate)
{
    price = price - (price • discountRate) / 100;
}
```

After calling the method, nothing changed; the value `productAPrice` is still the same. Every parameter passed to this method has a copy of the original variable value.

So, we use another approach by defining the `CalculateDiscount` method:

```csharp
public double productANewPrice = CalculateDiscount(ProductAPrice, discountRate);

public static double CalculateDiscount(double price, int discountRate) {
    return price - (price * discountRate) / 100;
}
```

In this approach, we defined a method that returns the new price after applying the discount, assigning this value to a new variable to use later in our program.

Here we passed the price and discount rate as individual parameters and got a new value to deal with. But what if we need to modify the original variable itself? To handle this scenario, we pass the price by reference.

## Passing by Reference

In general, passing by reference means you pass a reference that refers to an object. Therefore, we use the variable directly without creating any new copy. This technique is useful in many scenarios. This approach is straightforward in C#. The `ref` keyword allows us to access the data and make changes that persist.

### ref Keyword

Let's clear things out/ All objects we create from classes are reference-type variable that passed by reference by default, and all objects we create from a `struct` are value-type variables that passed by value by default.

Going back to our code, let's update the price within our `UpdatePriceByPercentByRef` method:

```csharp
UpdatePriceByPercentByRef(ref productAPrice, discountRate);

public static void UpdatePriceByPercentByRef(ref double price, int discountRate) {
    price = price - (price * discountRate) / 100;
}
```

We defined `UpdatePriceByPercentByRef` method with two parameters. The first `double` prefixed with the `ref` keyword allows us to use it by reference. On the other hand, the second parameter, an `int`, is passed by value. When we call the method, we pass the `productAPrice` variable prefixed with the `ref` keyword (this is required or throws a compile error). After calling this method, the value of `productAPrice` is updated.

### out Keyword

Here, if `productAPrice` is not initialized before passing it as a `ref` parameter, we encounter an error. This is true because we are trying to use a reference to an uninitialized variable. But, we can use the `out` keyword to use the variable with no need to initialize it. Let's see how to do that:

```csharp
double price;
MakeItZero(out price);

public static void MakeItZero(out double price) {
    price = 0;
}
```

Here, we assigned the unassigned variable `price` to zero.

### Arrays

Now, let's use an array of double prices to increase them by 10 percent each:

```csharp
double[] prices = { 30, 15, 21.5, 50 };

UpdatePrices(prices, 10);

public static void UpdatePrices(double[] prices, int rate) {
    for (int i = 0; i < prices.Length; i++)
    {
        prices[i] = prices[i] + prices[i] * rate / 100;
    }
}
```

We defined `UpdatePrices` method that takes an array of `double` and an `int`. It updates the values in the array by increasing or decreasing them based on the given rate. After this, we define prices as `double[]` and initialize with values. Then, we call the `UpdatePrices` method and pass the prices array to it. Note that the `ref` keyword is not required. Finally, all the values in the array increased by 10%.

### Classes and Objects

Let's create a method that takes a product and an int discount rate to update its price:

```csharp
public static void ApplyDiscount(Product product, int discountRate)
{
    product.Price -= (product.Price * discountRate) / 100;
}
```

Here, there is no need to use the `ref` keyword and the price is updated after calling the method.

### ref readonly modifier

Then we have `ref readonly` which allows referencing a variable without permitting its value to be changed. The question arises: why use it?

We use it to indicate that a large `struct` should be passed by reference for reasons.

The ref modifier introduced in C# 12, offers a balance between and safety.

## Key Differences and Considerations

Passing by value is the default behavior for value-type and struct-type variables, and passing by reference is the default behavior for class-type variables or arrays.

We pass by reference when we need to modify the actual value or state, or when we want to gain more performance dealing with large struct-type variables. Being able to use the `ref readonly` modifier also avoids unnecessary copying and accesses the heap memory address more safely without allowing modifications.

## Conclusion

Passing by value means any modifications in the method body do not affect the original variable value.

Passing by reference means passing the original data location in memory. That means any modifications within the method affect the original variable value.

Built-in types and struct types in C# are passed by value by default. Passing by reference is the default behavior for arrays and classes.

When passing and array or an object to a method, the method gets a reference to the entire object in the memory

We use the `ref` keyword to pass variables by reference, and the `out` keyword to define a method that returns values by reference.

Consider data size and the need for modification. We use passing by value for small data and passing by reference for large object to improve performance and control the modifications.

Finally, passing by reference can introduce complexity. Use it judiciously, and always with proper data handling practices.