What is the usage of ref, out, and in keywords in C#?

In C#, method parameters can be passed using different modifiers that control how arguments are handled. The ref, out, and in keywords allow you to pass parameters by reference rather than by value, each serving different purposes and having specific rules.

By default, C# passes arguments by value, meaning a copy of the value is created. Changes made inside the method don't affect the original variable.

Default Parameter Passing (By Value)

Value Types

When passing value types, a copy is made and modifications inside the method don't affect the original variable −

using System;

class Program {
   static void Main() {
      int number = 8;
      Increase(number);
      Console.WriteLine("Original: " + number);
   }
   
   static void Increase(int num) {
      num = num + 1;
      Console.WriteLine("Inside method: " + num);
   }
}

The output of the above code is −

Inside method: 9
Original: 8

Reference Types

For reference types, the reference is copied by value. You can modify the object's properties, but reassigning the parameter doesn't affect the original reference −

using System;

class User {
   public string Name { get; set; }
   public int Salary { get; set; }
}

class Program {
   static void Main() {
      var john = new User { Name = "John", Salary = 50000 };
      Promote(john);
      Console.WriteLine("After promotion: " + john.Salary);
      
      SetToNull(john);
      Console.WriteLine("After null assignment: " + (john != null ? john.Salary.ToString() : "null"));
   }
   
   static void Promote(User u) {
      u.Salary += 10000;
   }
   
   static void SetToNull(User u) {
      u = null; // Only affects the local parameter
   }
}

The output of the above code is −

After promotion: 60000
After null assignment: 60000

The ref Modifier

The ref keyword passes parameters by reference, allowing the method to modify the original variable. Both the parameter and argument refer to the same memory location.

Syntax

methodName(ref variableName);

static void methodName(ref DataType parameter) {
   // can read and modify parameter
}

Example

using System;

class User {
   public string Name { get; set; }
   public int Salary { get; set; }
}

class Program {
   static void Main() {
      int number = 5;
      DoubleValue(ref number);
      Console.WriteLine("Doubled value: " + number);
      
      var john = new User { Name = "John", Salary = 50000 };
      ReplaceUser(ref john);
      Console.WriteLine("New user: " + (john != null ? john.Name : "null"));
   }
   
   static void DoubleValue(ref int value) {
      value *= 2;
   }
   
   static void ReplaceUser(ref User user) {
      user = new User { Name = "Jane", Salary = 75000 };
   }
}

The output of the above code is −

Doubled value: 10
New user: Jane

The out Modifier

The out keyword is similar to ref, but with key differences: the argument doesn't need initialization before passing, but must be assigned inside the method.

Syntax

methodName(out variableName);

static void methodName(out DataType parameter) {
   parameter = value; // must assign before method returns
}

Example

using System;

class Program {
   static void Main() {
      // Variable can be declared inline
      if (TryParseNumber("123", out int result)) {
         Console.WriteLine("Parsed number: " + result);
      }
      
      // Multiple out parameters
      GetMinMax(new int[] {3, 1, 4, 1, 5}, out int min, out int max);
      Console.WriteLine("Min: " + min + ", Max: " + max);
   }
   
   static bool TryParseNumber(string input, out int number) {
      return int.TryParse(input, out number);
   }
   
   static void GetMinMax(int[] array, out int min, out int max) {
      min = array[0];
      max = array[0];
      foreach (int value in array) {
         if (value < min) min = value;
         if (value > max) max = value;
      }
   }
}

The output of the above code is −

Parsed number: 123
Min: 1, Max: 5

The in Modifier

The in keyword passes parameters by reference but makes them read-only inside the method. This avoids copying large value types while preventing accidental modifications.

Syntax

methodName(in variableName);

static void methodName(in DataType parameter) {
   // can read parameter but cannot modify it
}

Example

using System;

struct LargeStruct {
   public int X, Y, Z;
   public double Value1, Value2, Value3;
   
   public LargeStruct(int x, int y, int z) {
      X = x; Y = y; Z = z;
      Value1 = x * 1.5;
      Value2 = y * 2.0;
      Value3 = z * 0.5;
   }
}

class Program {
   static void Main() {
      var largeData = new LargeStruct(10, 20, 30);
      double sum = CalculateSum(in largeData);
      Console.WriteLine("Sum: " + sum);
      Console.WriteLine("Original X: " + largeData.X);
   }
   
   static double CalculateSum(in LargeStruct data) {
      // data.X = 100; // This would cause a compile error
      return data.Value1 + data.Value2 + data.Value3;
   }
}

The output of the above code is −

Sum: 70
Original X: 10

Comparison

Modifier Must Initialize Before Must Assign Inside Method Can Modify Use Case
ref Yes No Yes Two-way parameter passing
out No Yes Yes Multiple return values
in Yes No No Read-only reference for large structs

Conclusion

The ref, out, and in modifiers provide different ways to pass parameters by reference in C#. Use ref for two-way communication, out for multiple return values, and in for efficient read-only access to large value types. Each serves specific scenarios while maintaining type safety and performance optimization.

Updated on: 2026-03-17T07:04:36+05:30

659 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements