수색…


통사론

  • 참조로 전달 : public void Double (ref int numberToDouble) {}

비고

소개

값 유형

값 유형은 둘 중 더 간단합니다. 값 유형은 종종 데이터 자체를 나타내는 데 사용됩니다. 3D 공간의 정수, 부울 또는 점은 모두 좋은 값 유형의 예입니다.

값 유형 (구조체)은 struct 키워드를 사용하여 선언됩니다. 새로운 구조체를 선언하는 방법의 예는 구문 섹션을 참조하십시오.

일반적으로 값 유형을 선언하는 데 사용되는 2 개의 키워드가 있습니다.

  • 구조물
  • 열거 형

참조 유형

참조 유형은 약간 더 복잡합니다. 참조 유형은 객체 지향 프로그래밍의 의미에서 전통적인 객체입니다. 그래서, 상속 (및 그 혜택)을 지원하고 finalizers도 지원합니다.

C #에서는 일반적으로 다음과 같은 참조 유형이 있습니다.

  • 수업
  • 대표자들
  • 인터페이스

새 참조 유형 (클래스)은 class 키워드를 사용하여 선언됩니다. 예를 들어, 새 참조 유형을 선언하는 방법에 대한 구문 섹션을 참조하십시오.

주요 차이점

참조 유형과 값 유형 간의 주요 차이점은 아래에서 확인할 수 있습니다.

값 유형은 스택에 있으며, 참조 유형은 힙에 있습니다

이것은 종종 언급되는 두 가지 차이점이지만 실제로 C #에서 int와 같은 값 유형을 사용하면 프로그램은 해당 변수를 사용하여 해당 값을 직접 참조합니다. int mine = 0이라고하면, 변수 mine은 0을 직접 참조하여 효율적입니다. 그러나 참조 유형은 실제로 기본 오브젝트에 대한 참조를 보유합니다 (이름에서 알 수 있듯이). 이는 C ++와 같은 다른 언어의 포인터와 유사합니다.

이 효과는 즉시 느낄 수는 없지만 그 효과는 강력하고 미묘합니다. 예를 들어 다른 곳에서 참조 유형을 변경하는 예를 참조하십시오.

이 차이가 다음과 같은 다른 차이점의 주된 원인이며, 알아 둘 가치가 있습니다.

값 유형은 메소드에서 변경할 때 변경되지 않으며 참조 유형은 변경됩니다.

값 유형이 매개 변수로 메소드에 전달되면 메소드가 값을 변경하는 경우 값은 변경되지 않습니다. 대조적으로 참조 유형을 동일한 메소드에 전달하고이를 변경하면 기본 객체가 변경되므로 그 같은 객체를 사용하는 다른 것들은 원래 값보다는 새로 변경된 객체를 가질 것입니다.

자세한 내용은 값 유형 대 메소드의 참조 유형에 대한 예제를 참조하십시오.

내가 그들을 바꾸고 싶다면?

"ref"키워드를 사용하여 메소드에 전달하기 만하면이 객체를 참조로 전달하게됩니다. 의미, 그것은 메모리에있는 동일한 대상입니다. 당신이하는 수정은 존중받을 것입니다. 예를 들어 참조로 전달하는 예제를 참조하십시오.

값 유형은 null 일 수 없으며 참조 유형은

꽤 많이 말하면, 참조 타입에 null을 할당 할 수 있습니다. 즉, 할당 한 변수에 실제로 할당 된 객체가 없을 수 있습니다. 그러나 값 유형의 경우 이는 불가능합니다. 그러나 Nullable을 사용하면 값 유형을 nullable로 허용 할 수 있습니다 (요구 사항 인 경우). 이것이 고려중인 사항이라면 클래스가 가장 좋은 접근 방식이 아닌지 여부를 강하게 생각하십시오. 유형.

다른 곳에서 값 변경하기

public static void Main(string[] args)
{
    var studentList = new List<Student>();
    studentList.Add(new Student("Scott", "Nuke"));
    studentList.Add(new Student("Vincent", "King"));
    studentList.Add(new Student("Craig", "Bertt"));

    // make a separate list to print out later
    var printingList = studentList; // this is a new list object, but holding the same student objects inside it

    // oops, we've noticed typos in the names, so we fix those
    studentList[0].LastName = "Duke";
    studentList[1].LastName = "Kong";
    studentList[2].LastName = "Brett";

    // okay, we now print the list
    PrintPrintingList(printingList);
}

private static void PrintPrintingList(List<Student> students)
{
    foreach (Student student in students)
    {
        Console.WriteLine(string.Format("{0} {1}", student.FirstName, student.LastName));
    }
}

오타가있는 학생 이름을 수정하기 전에 printingList 목록이 만들어 졌음에도 불구하고 PrintPrintingList 메서드는 여전히 수정 된 이름을 출력합니다.

Scott Duke
Vincent Kong
Craig Brett

두 목록 모두 동일한 학생에 대한 참조 목록을 보유하고 있기 때문입니다. 기본 학생 객체를 변경하면 두 목록 중 하나에 의해 용도로 전파됩니다.

학생 수업은 다음과 같습니다.

public class Student
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Student(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }
}

참조로 전달

값 유형과 메소드의 참조 유형이 제대로 작동하게하려면 메소드를 호출 할 때뿐만 아니라 참조로 전달할 매개 변수에 대해 메소드 서명에서 ref 키워드를 사용하십시오.

public static void Main(string[] args)
{
    ...
    DoubleNumber(ref number); // calling code
    Console.WriteLine(number); // outputs 8
    ...
}
public void DoubleNumber(ref int number)
{
    number += number;
}

이러한 변경 작업을 수행하면 숫자 업데이트가 예상대로 수행되므로 number에 대한 콘솔 출력은 8이됩니다.

ref 키워드를 사용하여 참조로 전달.

문서에서 :

C #에서는 인수를 값 또는 참조로 매개 변수에 전달할 수 있습니다. 참조로 전달하면 함수 멤버, 메서드, 속성, 인덱서, 연산자 및 생성자가 매개 변수의 값을 변경하고 호출 환경에서 변경 내용을 유지할 수 있습니다. 참조로 매개 변수를 전달하려면 ref 또는 out 키워드를 사용하십시오.

차이 refoutout 전달 된 파라미터와 함께 전달 함수 ends.in 콘트라스트 파라미터 전에 할당되는 것을 의미한다 ref 변경되거나 변경되지 않고 남아있을 수있다.

using System;

class Program
{
    static void Main(string[] args)
    {
        int a = 20;
        Console.WriteLine("Inside Main - Before Callee: a = {0}", a);
        Callee(a);
        Console.WriteLine("Inside Main - After Callee: a = {0}", a);
        
        Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a);
        CalleeRef(ref a);
        Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a);
     
        Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a);
        CalleeOut(out a);
        Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a);
        
        Console.ReadLine();
    }

    static void Callee(int a)
    {
        a = 5;
        Console.WriteLine("Inside Callee a : {0}", a);
    }

    static void CalleeRef(ref int a)
    {
        a = 6;
        Console.WriteLine("Inside CalleeRef a : {0}", a);
    }
    
    static void CalleeOut(out int a)
    {
        a = 7;
        Console.WriteLine("Inside CalleeOut a : {0}", a);
    }
}

출력 :

Inside Main - Before Callee: a = 20
Inside Callee a : 5
Inside Main - After Callee: a = 20
Inside Main - Before CalleeRef: a = 20
Inside CalleeRef a : 6
Inside Main - After CalleeRef: a = 6
Inside Main - Before CalleeOut: a = 6
Inside CalleeOut a : 7
Inside Main - After CalleeOut: a = 7

할당

var a = new List<int>();
var b = a;
a.Add(5);
Console.WriteLine(a.Count); // prints 1 
Console.WriteLine(b.Count); // prints 1 as well

(A)의 변수에 할당 List<int> 의 복사본을 만들지 않습니다 List<int> . 대신 List<int> 대한 참조를 복사합니다. 우리는 이러한 방식으로 참조 유형 을 사용하는 유형을 호출 합니다 .

메서드 매개 변수 ref 및 out과의 차이점

참조로 값 유형을 전달하는 방법에는 refout 두 가지가 있습니다. 차이점은 ref 로 전달하면 값을 초기화해야하지만 전달할 때는 초기화하지 말아야한다는 out 입니다. out 을 사용하면 메서드 호출 후에 변수에 값이 있음을 확인할 수 있습니다.

public void ByRef(ref int value)
{
    Console.WriteLine(nameof(ByRef) + value);
    value += 4;
    Console.WriteLine(nameof(ByRef) + value);
}

public void ByOut(out int value)
{
    value += 4 // CS0269: Use of unassigned out parameter `value'  
    Console.WriteLine(nameof(ByOut) + value); // CS0269: Use of unassigned out parameter `value'  

    value = 4;
    Console.WriteLine(nameof(ByOut) + value);
}

public void TestOut()
{
    int outValue1;
    ByOut(out outValue1); // prints 4

    int outValue2 = 10;   // does not make any sense for out
    ByOut(out outValue2); // prints 4
}

public void TestRef()
{
    int refValue1;
    ByRef(ref refValue1); // S0165  Use of unassigned local variable 'refValue'

    int refValue2 = 0;
    ByRef(ref refValue2); // prints 0 and 4

    int refValue3 = 10;
    ByRef(ref refValue3); // prints 10 and 14
}

캐치가 사용한다는 것입니다 out 매개 변수를 must 방법을 떠나기 전에 초기화 따라서 다음과 같은 방법으로 가능하다 ref 은 불가능 out :

public void EmtyRef(bool condition, ref int value)
{
    if (condition)
    {
        value += 10;
    }
}

public void EmtyOut(bool condition, out int value)
{
    if (condition)
    {
        value = 10;
    }
} //CS0177: The out parameter 'value' must be assigned before control leaves the current method

conditioncondition 되지 않으면 value 이 할당되지 않기 때문입니다.

ref 대 out 매개 변수

암호

class Program
{
    static void Main(string[] args)
    {
        int a = 20;
        Console.WriteLine("Inside Main - Before Callee: a = {0}", a);
        Callee(a);
        Console.WriteLine("Inside Main - After Callee: a = {0}", a);
        Console.WriteLine();

        Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a);
        CalleeRef(ref a);
        Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a);
        Console.WriteLine();

        Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a);
        CalleeOut(out a);
        Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a);
        Console.ReadLine();
    }

    static void Callee(int a)
    {
        a += 5;
        Console.WriteLine("Inside Callee a : {0}", a);
    }

    static void CalleeRef(ref int a)
    {
        a += 10;
        Console.WriteLine("Inside CalleeRef a : {0}", a);
    }

    static void CalleeOut(out int a)
    {
        // can't use a+=15 since for this method 'a' is not intialized only declared in the method declaration
        a = 25; //has to be initialized
        Console.WriteLine("Inside CalleeOut a : {0}", a);
    }
}

산출

Inside Main - Before Callee: a = 20
Inside Callee a : 25
Inside Main - After Callee: a = 20

Inside Main - Before CalleeRef: a = 20
Inside CalleeRef a : 30
Inside Main - After CalleeRef: a = 30

Inside Main - Before CalleeOut: a = 30
Inside CalleeOut a : 25
Inside Main - After CalleeOut: a = 25


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow