C # 7 : Out 변수의 밑줄 (_) 및 별표 (*)


79

여기 에서 C # 7의 새로운 변수 기능에 대해 읽었 습니다 . 두 가지 질문이 있습니다.

  1. 그것은 말한다

    우리는 _당신이 신경 쓰지 않는 매개 변수를 무시할 수 있도록 a 형태의 out 매개 변수로 "discards" 를 허용합니다.

    p.GetCoordinates(out var x, out _); // I only care about x
    

    Q : C # 7.0 이전 버전에서도 가능하기 때문에 이것은 정보 일 뿐이며 C # 7의 새로운 기능은 아닙니다.

    var _;
    if (Int.TryParse(str, out _))
    ...
    

    아니면 여기에 뭔가 빠졌나요?

  2. 동일한 블로그에서 언급 한대로 수행하면 내 코드에서 오류가 발생합니다.

    ~Person() => names.TryRemove(id, out *);
    

    *유효한 식별자가 아닙니다. Mads Torgersen의 감독 이요?


15
in out _ _은 변수가 아니므로 선언하지 않고 이름으로 사용할 수 없습니다. 에 int _있는 변수이다.
Evk

9
별표 와일드 카드는 C # 7의 최종 릴리스에 포함되지 않은 것 같습니다.
Michael Stum

3
@NikhilAgrawal 그러나 그것은 다른 구문입니다. 귀하의 질문에 당신은 사용 out _없이 var. 함께 var그것을 실제로 이전과 동일합니다.
Evk

2
@NikhilAgrawal은 실제로 이상한 이유로 컴파일됩니다. 그러나 디 컴파일 된 코드를 살펴보면이 할당은 완전히 제거되었습니다. 그리고 당신이 뭔가를한다면 Console.WriteLine(_)-이것은 그러한 변수가 없다고 주장하는 컴파일되지 않을 것입니다. 꽤 이상합니다. 더 많은 것 : 만약 당신이 같은 일을한다면 _ = SomeMethodCall(), 이것은 SomeMethodCall()컴파일 된 코드 로 대체 될 것 입니다. 그래서 결국 당신은 의미있는 의미로 그 변수를 실제로 사용할 수 없습니다.
Evk

답변:


111

C # 7에서 Discards 는 변수가 선언 될 때마다-이름에서 알 수 있듯이-결과를 버리는 데 사용할 수 있습니다. 따라서 폐기는 out 변수와 함께 사용할 수 있습니다.

p.GetCoordinates(out var x, out _);

표현식 결과를 버리는 데 사용할 수 있습니다.

_ = 42;

예에서

p.GetCoordinates(out var x, out _);
_ = 42;

_도입되는 변수가 없습니다 . 폐기가 사용되는 경우는 두 가지뿐입니다.

그러나 _범위에 식별자 가 있으면 폐기를 사용할 수 없습니다.

var _ = 42;
_ = "hello"; // error - a string cannot explicitly convert from string to int

이에 대한 예외는 _변수가 출력 변수로 사용되는 경우입니다. 이 경우 컴파일러는 또는 유형을 무시하고 var이를 폐기로 처리합니다.

if (p.GetCoordinates(out double x, out double _))
{
    _ = "hello"; // works fine.
    Console.WriteLine(_); // error: _ doesn't exist in this context.
}

이 경우 out var _또는 out double _이 사용되는 경우에만 발생합니다 . 사용 out _하면 기존 변수에 대한 참조로 처리됩니다 ( _예 : 범위에있는 경우).

string _;
int.TryParse("1", out _); // complains _ is of the wrong type

마지막 *으로이 표기법은 폐기에 대한 논의 초기에 제안 되었지만 _후자가 다른 언어에서 더 일반적으로 사용되는 표기법이기 때문에 포기되었습니다 .


나는 '의 ... 무슨 뜻 생각 _때문에에 , 후자는 ... 인'
martijnn2008

@ martijnn2008, 잘 발견되었습니다. 감사.
David Arno

1
나는 이것이 묵시적이라고 생각하지만 폐기의 요점은 예상 가치가 실제로 저장되지 않는다는 것입니까?
Sinjai

알리는 _ = 42"폐기를 [S] 식의 결과가"때문에, 오해의 소지가되는 _ = 42값으로 표현 자체가 42너무 벌어 실제 폐기가 없습니다. _ = 42;성명도 있기 때문에 여전히 차이 가 있지만 42;일부 상황에서는 중요하지 않습니다.
Jeroen Mostert 2018

1
구문은 괜찮습니다. _ = 42이 폐기의 요점이 무엇인지 보여주지 못하는 것입니다. , 유용함) 표현은 저장하지 않고 괜찮습니다. 나는 즉시 유용한 예제를 생각할 수 없습니다 (그리고 하나가 있는지 또는 이것이 문법의 일관성의 결과인지 모르겠습니다).
Jeroen Mostert 2018

30

_C # 7에서 Discard 연산자의 또 다른 예 는 최근 C # 7에서 추가 된 문 에서 유형의 변수 를 패턴 일치 시키는 것입니다 .objectswitch

암호:

static void Main(string[] args)
{
    object x = 6.4; 
    switch (x)
    {
        case string _:
            Console.WriteLine("it is string");
            break;
        case double _:
            Console.WriteLine("it is double");
            break;
        case int _:
            Console.WriteLine("it is int");
            break;
        default:
            Console.WriteLine("it is Unknown type");
            break;
    }

    // end of main method
}

이 코드는 유형과 일치하고 case ... _.


14

더 궁금해

다음 스 니펫을 고려하십시오.

static void Main(string[] args)
{
    //....
    int a;
    int b;

    Test(out a, out b);
    Test(out _, out _);    
    //....
}

private static void Test(out int a, out int b)
{
    //...
}

이것은 무슨 일이 일어나고 있는지 :

...

13:             int  a;
14:             int  b;
15: 
16:             Test(out a, out b);
02340473  lea         ecx,[ebp-40h]  
02340476  lea         edx,[ebp-44h]  
02340479  call        02340040  
0234047E  nop  
    17:             Test(out _, out _);
0234047F  lea         ecx,[ebp-48h]  
02340482  lea         edx,[ebp-4Ch]  
02340485  call        02340040  
0234048A  nop 

...

이면에서 볼 수 있듯이 두 통화는 같은 일을합니다.

@ Servé Laurijssen이 지적했듯이 멋진 점은 일부 값에 관심이없는 경우 편리한 변수 를 미리 선언 할 필요가 없다는 것입니다.


3
호출하는 함수에 여전히 out 변수에 대한 슬롯이 필요하기 때문에 IL 동일해야합니다. 새로운 폐기 구문을 사용하면 컴파일러가 지역 변수 (또는 부족)에 대해 더 많은 가정을 할 수있어 더 효율적으로 사용할 수 있습니다 (적어도 이론적으로는 최적화가 이미 있는지 모르겠습니다). 현재 컴파일러에서).
찌르기

9

첫 번째 질문에 대해

C # 7.0 이전 버전에서도 그렇게 할 수 있기 때문에 이것은 정보 일 뿐이며 C # 7의 새로운 기능은 아닙니다.

var _;
if (Int.TryParse(str, out _))
    // ...

참신한 점은 _더 이상 표현식 내부 또는 외부 에 선언 할 필요가 없으며 입력 만하면 된다는 것입니다.

int.TryParse(s, out _);

C # 7 이전에이 하나의 라이너를 시도해보십시오.

private void btnDialogOk_Click_1(object sender, RoutedEventArgs e)
{
     DialogResult = int.TryParse(Answer, out _);
}

7
추가하려면 : 밑줄은 출력 매개 변수가 여러 개인 메소드에 대해 정말 잘 작동합니다. 예를 들어 출력 매개 변수 SomeMethod(out _, out _, out three)가 3 개 있지만, unused1, unused2등의 변수를 만들 필요없이 처음 두 개는 버립니다 .
Michael Stum

@MichaelStum : 여기서 무슨 일이 일어나고 있습니까? if (SomeMethod(out _, out _, out _)) _ = 5; 그것은 _무엇을 의미합니까?
Nikhil Agrawal

4
@NikhilAgrawal을 _사용하더라도 전혀 변수 가 없을 것 out var _입니다. 밑줄은 결과를 버리기 위해 특수한 경우 인 것 같습니다.
Michael Stum

0

C # 7.0 (2017 년 3 월경 Visual Studio 2017)에서는 다음 컨텍스트의 할당에서 삭제가 지원됩니다.

  • 튜플 및 객체 분해.
  • is 및 switch와 패턴 일치 .
  • out 매개 변수가있는 메서드를 호출합니다.
  • _가 범위에없는 경우 독립형 _입니다.

기타 유용한 정보

  • 폐기는 메모리 할당을 줄일 수 있습니다. 코드의 의도를 명확하게하기 때문에 가독성과 유지 관리 성을 향상시킵니다.
  • _도 유효한 식별자입니다. 지원되는 컨텍스트 외부에서 사용되는 경우

간단한 예 : 여기에서는 첫 번째 및 두 번째 매개 변수를 사용하지 않고 세 번째 매개 변수 만 필요합니다.

(_, _, area) = city.GetCityInformation(cityName);

현대적인 스위치 케이스 패턴 매칭을 사용한 스위치 케이스의 고급 예 ( 소스 )

switch (exception)                {
case ExceptionCustom exceptionCustom:       
        //do something unique
        //...
    break;
case OperationCanceledException _:
    //do something else here and we can also cast it 
    //...
    break;
default:
    logger?.Error(exception.Message, exception);
    //..
    break;

}


0

Q : ... C # 7.0 이전 버전에서도 가능합니다.

var _;
if (Int.TryParse(str, out _))

아니면 여기에 뭔가 빠졌나요?

그것은 같은 것이 아닙니다.
코드가 할당되고 있습니다.

C # 7.0에서 _ 변수 가 아니므 로 컴파일러에게 값을 삭제하도록 지시합니다
( _ 를 변수로 선언 하지 않은 경우 ... 그렇게하면 삭제 기호 대신 변수가 사용됨).

예 : 동일한 코드 줄 에서 _ 를 sting 및 int로 사용할 수 있습니다 .

string a; 
int b;
Test(out a, out b);
Test(out _, out _);

//...

void Test(out string a, out int b)
{
   //...
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.