Computer >> 컴퓨터 >  >> 프로그램 작성 >> C#

C#에서 ref, out 및 in 키워드의 사용법은 무엇입니까?

<시간/>

C#에서 대부분의 메서드는 메서드에 제공해야 하는 데이터를 정의하는 0개 이상의 매개 변수를 가질 수 있습니다. 메서드를 호출하는 모든 코드는 데이터(인수라고 함)를 메서드에 전달해야 합니다. 메소드는 입력을 매개변수로 선언하고 인수 형식으로 코드를 호출하여 제공됩니다.

예를 들어, 다음 메소드와 후속 메소드 호출을 고려하십시오.

static void Greet(string greeting){
   Console.WriteLine(greeting);
}
...
Greet("Hello");

위의 예에서 Greeting은 Greet() 메서드의 매개변수이고 "Hello"는 메서드에 전달된 인수입니다.

메소드를 호출하고 인수를 전달하면 값으로 전달됩니다. 즉, 메소드에 전달될 때 값의 복사본이 생성됩니다. 메소드 내부의 인수에 대한 변경 사항은 원래 변수에 반영되지 않습니다.

using System;
int number = 8;
Increase(number);
Console.WriteLine(number); // prints 8
static void Increase(int num){
   num = num + 1;
   Console.WriteLine(num); // prints 9
}

개체와 같은 참조 유형 변수를 전달할 때 C#은 여전히 ​​참조를 복사합니다. 변수가 실제 객체가 아닌 참조를 보유하기 때문입니다. 따라서 참조 변수의 복사본이 전달되더라도 둘 다 메모리에서 동일한 개체를 참조합니다. 따라서 메서드 내부의 변수에 의해 개체에 적용된 모든 변경 사항은 메서드 외부의 변수에서 볼 수 있습니다.

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 60000
static void Promote(User u){
   u.Salary += 10000;
   Console.WriteLine(u.Salary); // prints 60000
}

그러나 메소드 내에서 변수 값 자체를 변경하면 실제 객체가 아닌 복사본만 변경되기 때문에 해당 변경사항이 메소드 외부에 반영되지 않습니다. 예를 들어 메서드 내에서 null에 인수를 할당할 수 있으며 실제 변수는 변경되지 않은 상태로 유지됩니다.

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 50000
static void Promote(User u){
   u = null;
}

C#은 메소드의 매개변수를 제어할 수 있는 세 가지 다른 수식어 키워드를 허용합니다.

참조 수정자

C#을 사용하면 ref를 사용하여 참조로 매개변수를 전달할 수 있습니다. 수정자. 전달되는 변수가 참조 유형 또는 값 유형에 속하는지 여부는 중요하지 않습니다. 매개변수와 인수는 모두 동일한 메모리 위치를 참조합니다.

다음 예에서 인수 u를 null로 설정하면 john 변수도 null이 되어 null 참조 예외가 발생합니다.

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(ref john);
Console.WriteLine(john.Salary); // throws System.NullReferenceException
static void Promote(ref User u){
   u = null;
}

ref 수정자와 함께 전달된 인수는 전달되기 전에 초기화되어야 합니다.

아웃 수정자

를 제외하고 ref 수정자와 유사합니다.
  • 인수는 함수에 들어가기 전에 초기화할 필요가 없습니다.

  • 인수는 함수에서 나오기 전에 초기화(할당)되어야 합니다.

아래 예에서 Hire 함수는 out 수정자를 통해 전달된 새 사용자 개체를 초기화합니다. 변수는 변수 john이 Hire 메서드를 호출할 때 즉석에서 선언됩니다.

using System;
Hire(out User john);
Console.WriteLine(john.Salary); // prints 50000
static void Hire(out User u){
   u = new User{
      Name = "John",
      Salary = 50000
   };
}

참조 좋아요 수정자, out으로 표시된 변수 수정자는 참조로 전달됩니다.

종종 외부 변수는 다음과 같이 함수에서 여러 반환 값을 가져오는 데 사용됩니다. -

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
bool shouldPromote = Raise(john.Salary, out double hike);
Console.WriteLine(shouldPromote); // True
Console.WriteLine($"Hike Amount = {hike}"); // prints 5000
static bool Raise(int salary, out double hike){
   hike = salary * 0.1;
   return hike < 7000;
}

in 수정자

ref와 유사합니다. 그리고 in을 허용하는 메서드를 제외하고 매개변수 인수의 값은 인수를 수정할 수 없습니다. 시도하면 C# 컴파일러가 컴파일 시간 오류를 생성합니다.

안에 매개변수는 컴파일러가 큰 값 유형의 메모리를 매개변수 변수로 복사하는 것과 동시에 개체가 우발적으로 수정되는 것을 방지합니다. 이것은 메소드에 큰 값 유형을 전달할 때 매우 유용합니다.

var point = new Coord();
Verify(point);
static void Verify(in Coord c){
   // error: Cannot assign to variable 'in Coord' because it is a readonly variable
   c = new Coord();
}
struct Coord{
   public int X;
   public int Y;
}

using System;
class Program{
   static void Main(){
      int number = 8;
      Increase(number);
      Console.WriteLine(number); // prints 8
      var john = new User { Name = "John", Salary = 50000 };
      Promote(john);
      Console.WriteLine(john.Salary); // prints 60000
      Leave(john);
      Console.WriteLine(john.Salary); // prints 60000

      LeaveByRef(ref john);
      Console.WriteLine(john?.Salary); // prints nothing

      User dave;
      Hire(out dave);
      Console.WriteLine(dave.Salary); // prints 50000
   }
   static void Increase(int num){
      num = num + 1;
      Console.WriteLine(num); // prints 9
   }
   static void Promote(User u){
      u.Salary += 10000;
      Console.WriteLine(u.Salary); // prints 60000
   }
   static void Leave(User u){
      u = null;
   }
   static void LeaveByRef(ref User u){
      u = null;
   }
   static void Hire(out User u){
      u = new User{
         Name = "John",
         Salary = 50000
      };  
   }
}
class User{
   public string Name { get; set; }
   public int Salary { get; set; }
}

출력

9
8
60000
60000
60000
50000