[C#] vs ref vs out에서 사용하는 경우

다른 날에 매개 변수 키워드 out대신을 사용해야한다고 누군가에게 물었습니다 ref. 필자는 ( ref와) out키워드 ( 이전요청 된 )의 차이점을 이해하지만 가장 좋은 설명은 ref== in및 것으로 보이지만 out, 항상 사용해야 out하고 사용 하지 않아야하는 (가설 또는 코드) 예제는 무엇입니까 ref?

ref더 일반적 이기 때문에 왜 사용하고 싶 out습니까? 그것은 단지 구문 설탕인가?



답변

당신은 사용해야 out당신이 필요로하지 않는 ref.

예를 들어 다른 프로세스와 같이 데이터를 마샬링해야 할 때 큰 차이가 생겨 비용이 많이들 수 있습니다. 따라서 메소드가 값을 사용하지 않을 때 초기 값을 마샬링하는 것을 피하고 싶습니다.

그 외에도, 선언의 독자 나 초기 값이 관련성이 있는지 (또는 잠재적으로 보존되어 있는지) 버리는 지 표시합니다.

사소한 차이로 out 매개 변수를 초기화 할 필요가 없습니다.

out:

string a, b;
person.GetBothNames(out a, out b);

여기서 GetBothNames는 두 개의 값을 원자 적으로 검색하는 방법이며 a와 b가 무엇이든 동작을 변경하지 않습니다. 호출이 하와이의 서버로 이동하면 여기에서 초기 값을 하와이로 복사하는 것은 대역폭 낭비입니다. 심판을 사용하는 비슷한 발췌 문장 :

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

a와 b의 초기 값이 관련이있는 것처럼 보이기 때문에 독자를 혼동시킬 수 있습니다 (메소드 이름이 그렇지 않다는 것을 나타내더라도).

ref:

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

여기서 초기 값은 방법과 관련이 있습니다.


답변

매개 변수가 사용 중이 아님을 나타 내기 위해 사용하십시오. 이렇게하면 호출자가 항상 매개 변수를 초기화하고 있음을 이해하는 데 도움이됩니다.

또한 ref 및 out은 값 유형만을위한 것이 아닙니다. 또한 메소드 내에서 참조 유형이 참조하는 오브젝트를 재설정 할 수 있습니다.


답변

의미 상 ref“입력”기능과 “출력”기능을 모두 제공하는 반면 out“출력”기능 만 제공 한다는 점에서 맞습니다 . 고려해야 할 사항이 있습니다.

  1. out매개 변수를받는 메소드는 리턴하기 전에 어느 시점에서 변수에 값을 지정해야합니다. 와 같은 Dictionary<K,V>기능을 가진 키 / 값 데이터 저장 클래스 중 일부에서이 패턴을 찾을 수 있습니다 TryGetValue. 이 함수는 out검색 될 때 값이 유지 되는 매개 변수를 사용합니다. 이 값을 전달하는 호출자에 대한 이해가되지 것입니다 그래서,이 기능을 out이의 경우 ( “실제”데이터가없는 경우에도 일부 값이 호출 후 변수가 될 것이라는 점을 보증하는 데 사용됩니다 TryGetValue열쇠는 존재하지 않습니다).
  2. outref상호 운용성 코드를 처리 할 때 매개 변수가 다르게 마샬링됩니다

또한 참조 유형과 값 유형은 값의 특성이 다르지만 응용 프로그램의 모든 변수는 참조 유형의 경우에도 값을 보유하는 메모리 위치를 가리 킵니다 . 참조 유형의 경우 메모리의 해당 위치에 포함 된 값이 다른 유형입니다.메모리 위치. 함수에 값을 전달하거나 다른 변수 할당을 수행하면 해당 변수의 값이 다른 변수에 복사됩니다. 값 형식의 경우 형식의 전체 내용이 복사됩니다. 참조 유형의 경우 메모리 위치가 복사됨을 의미합니다. 어느 쪽이든 변수에 포함 된 데이터의 사본을 작성합니다. 이것이 가지고있는 유일한 관련성은 할당 의미론을 다룬다. 변수를 할당하거나 값을 기준으로 전달할 때 (기본값), 원래 (또는 새) 변수에 새를 할당하면 다른 변수에 영향을 미치지 않습니다. 참조 유형의 경우 예, 인스턴스 변경양쪽에서 사용할 수 있지만 실제 변수는 다른 메모리 위치에 대한 포인터 일뿐입니다. 변수의 내용 (메모리 위치)은 실제로 변경되지 않았습니다.

ref키워드 와 함께 전달 하면 원래 변수 함수 매개 변수가 실제로 동일한 메모리 위치를 가리 키게됩니다. 이는 할당 시맨틱에만 영향을 미칩니다. 새 값이 변수 중 하나에 할당되면 다른 값이 동일한 메모리 위치를 가리 키기 때문에 새 값이 다른쪽에 반영됩니다.


답변

컴파일 컨텍스트에 따라 다릅니다 (아래 예 참조).

outref참조로 전달 모두 나타내고 변수 아직 ref마샬링의 맥락에서 중요한 차이가있다 전달되기 전에 초기화되는 변수 요구 (상호 운용성 : UmanagedToManagedTransition 또는 그 반대로)을

MSDN은 다음과 같이 경고합니다 .

참조에 의한 전달 개념과 참조 유형의 개념을 혼동하지 마십시오. 두 개념은 동일하지 않습니다. 메소드 매개 변수는 값 유형인지 참조 유형인지에 관계없이 ref로 수정할 수 있습니다. 참조로 전달 될 때 값 유형의 boxing이 없습니다.

공식 MSDN 문서에서 :

out 키워드는 인수가 참조로 전달되도록합니다. ref는 변수가 전달되기 전에 초기화되어야한다는 점을 제외하고는 ref 키워드와 유사합니다.

ref 키워드는 인수가 값이 아닌 참조로 전달되도록합니다. 참조로 전달하면 메소드의 매개 변수에 대한 변경 사항이 호출 메소드의 기본 인수 변수에 반영됩니다. 참조 매개 변수의 값은 항상 기본 인수 변수의 값과 같습니다.

인수가 할당 될 때 out과 ref가 실제로 동일한 지 확인할 수 있습니다.

CIL 예 :

다음 예를 고려하십시오

static class outRefTest{
    public static int myfunc(int x){x=0; return x; }
    public static void myfuncOut(out int x){x=0;}
    public static void myfuncRef(ref int x){x=0;}
    public static void myfuncRefEmpty(ref int x){}
    // Define other methods and classes here
}

CIL에서의 지침 myfuncOut과는 myfuncRef예상대로 동일하다.

outRefTest.myfunc:
IL_0000:  nop
IL_0001:  ldc.i4.0
IL_0002:  starg.s     00
IL_0004:  ldarg.0
IL_0005:  stloc.0
IL_0006:  br.s        IL_0008
IL_0008:  ldloc.0
IL_0009:  ret

outRefTest.myfuncOut:
IL_0000:  nop
IL_0001:  ldarg.0
IL_0002:  ldc.i4.0
IL_0003:  stind.i4
IL_0004:  ret

outRefTest.myfuncRef:
IL_0000:  nop
IL_0001:  ldarg.0
IL_0002:  ldc.i4.0
IL_0003:  stind.i4
IL_0004:  ret

outRefTest.myfuncRefEmpty:
IL_0000:  nop
IL_0001:  ret         

nop : 작업 없음, ldloc : 로컬로드, stloc : 스택 로컬, ldarg :로드 인수, bs.s : 대상에서 분기로 ….

( CIL 명령어 목록 참조 )


답변

아래는 C # Out Vs Ref 의이 코드 프로젝트 기사에서 가져온 참고 사항입니다.

  1. 함수 나 메소드에서 여러 개의 출력을 기대할 때만 사용해야합니다. 구조에 대한 생각도 동일한 옵션이 될 수 있습니다.
  2. REF 및 OUT은 발신자에서 수신자로 또는 그 반대로 데이터가 전달되는 방식을 나타내는 키워드입니다.
  3. REF에서 데이터는 양방향으로 전달됩니다. 발신자에서 수신자로 또는 그 반대로.
  4. In Out 데이터는 수신자로부터 발신자에게 한 방향으로 만 전달됩니다. 이 경우 발신자가 수신자에게 데이터를 보내려고하면 간과 / 거부됩니다.

당신이 시각적 인 사람이라면 실제로 https://www.youtube.com/watch?v=lYdcY5zulXA 의 차이점을 보여주는이 유튜브 비디오를 참조 하십시오

아래 이미지는 차이점을 더 시각적으로 보여줍니다.

C # 출력 대 Ref


답변

ref매개 변수를 읽고 쓰려 는 경우 사용해야 합니다. out작성하려는 경우에만 사용해야 합니다. 실제로, out하나 이상의 반환 값이 필요하거나 출력에 일반 반환 메커니즘을 사용하지 않으려는 경우에 사용됩니다 (그러나 드문 경우 임).

이러한 사용 사례를 지원하는 언어 역학이 있습니다. Ref매개 변수는 메소드에 전달되기 전에 초기화되어야하고 (읽기-쓰기라는 사실에 중점을 두어) out값을 지정하기 전에는 매개 변수를 읽을 수 없으며 마지막에 기록되도록 보장됩니다. 방법 (쓰기 전용이라는 사실에 중점을 둡니다). 이러한 원칙을 위반하면 컴파일 타임 오류가 발생합니다.

int x;
Foo(ref x); // error: x is uninitialized

void Bar(out int x) {}  // error: x was not written to

예를 들어, int.TryParsea를 반환하고 매개 변수를 bool허용합니다 out int.

int value;
if (int.TryParse(numericString, out value))
{
    /* numericString was parsed into value, now do stuff */
}
else
{
    /* numericString couldn't be parsed */
}

숫자 결과와 변환 성공 여부를 나타내는 두 가지 값을 출력해야하는 상황의 명확한 예입니다. CLR의 저자는 이전에 가능했던 out것에 신경 쓰지 않기 때문에 여기 에서 선택하기로 결정했습니다 int.

의 경우 ref다음을 볼 수 있습니다 Interlocked.Increment.

int x = 4;
Interlocked.Increment(ref x);

Interlocked.Increment원자 적으로의 값을 증가시킵니다 x. x증가 시키기 위해 읽어야하므로 ref보다 적절한 상황 입니다. 당신 x은 그것이 전달되기 전에 무엇 에 전적으로 관심 이 Increment있습니다.

다음 버전의 C #에서는 out매개 변수로 변수 를 선언 하여 출력 전용 특성을 더욱 강조 할 수도 있습니다 .

if (int.TryParse(numericString, out int value))
{
    // 'value' exists and was declared in the `if` statement
}
else
{
    // conversion didn't work, 'value' doesn't exist here
}


답변

out더 제약 버전입니다 ref.

메소드 본문에서 메소드 out를 종료하기 전에 모든 매개 변수 에 지정해야합니다 . 또한 out매개 변수에 지정된 값 은 무시되는 반면 값을 지정 ref해야합니다.

따라서 out다음을 수행 할 수 있습니다.

int a, b, c = foo(out a, out b);

여기서 refa와 b를 할당해야합니다.