왜 'out'키워드가 서로 다른 두 가지 상황에서 사용됩니까?


11

C #에서는 out키워드를 두 가지 방식으로 사용할 수 있습니다.

  1. 인수가 참조전달되는 매개 변수 수정 자

    class OutExample
    {
        static void Method(out int i)
        {
            i = 44;
        }
        static void Main()
        {
            int value;
            Method(out value);
            // value is now 44
        }
    }
    
  2. 공분산 을 지정 하는 유형 매개 변수 수정 자 입니다.

    // Covariant interface. 
    interface ICovariant<out R> { }
    
    // Extending covariant interface. 
    interface IExtCovariant<out R> : ICovariant<R> { }
    
    // Implementing covariant interface. 
    class Sample<R> : ICovariant<R> { }
    
    class Program
    {
        static void Test()
        {
            ICovariant<Object> iobj = new Sample<Object>();
            ICovariant<String> istr = new Sample<String>();
    
            // You can assign istr to iobj because 
            // the ICovariant interface is covariant.
            iobj = istr;
        }
    }
    

내 질문은 : 왜?

초보자 에게는 둘 사이의 연결 이 직관적으로 보이지 않습니다 . 제네릭을 사용하는 것은 참조로 전달하는 것과 관련이없는 것 같습니다.

나는 먼저 out참조로 인수를 전달하는 것과 관련하여 무엇 을 배웠으며 , 이것은 제네릭과의 공분산 정의에 대한 이해를 방해했습니다.

내가 누락 된 이러한 사용 사이에 연결이 있습니까?


5
System.Func<in T, out TResult>delegate 의 공분산 및 반공산 사용을 보면 연결이 약간 더 이해 될 수 있습니다 .
rwong

4
또한 대부분의 언어 디자이너는 키워드 수를 최소화하려고 시도하고 코드베이스가 큰 일부 기존 언어로 새 키워드를 추가하는 것은
어렵습니다 (

답변:


20

연결이 있지만 약간 느슨합니다. C #에서 키워드 'in'및 'out'은 이름이 입력 및 출력을 나타냅니다. 이것은 출력 매개 변수의 경우 매우 분명하지만 템플릿 매개 변수와 관련이있는 것은 덜 명확합니다.

Liskov 대체 원칙을 살펴 보겠습니다 .

...

Liskov의 원칙은 최신 객체 지향 프로그래밍 언어 (일반적으로 유형이 아닌 클래스 수준에서 채택 된 특성에 대한 일부 표준 요구 사항을 부과합니다.

  • 하위 유형의 메소드 인수의 공분산
  • 하위 유형의 반환 유형 공분산

...

불확실성이 입력과 연관되고 공분산이 출력과 어떻게 연관되는지보십시오. C #에서 템플릿 변수를 out공변량으로 만들기 위해 플래그를 지정 하면 언급 된 유형 매개 변수가 출력 (함수 반환 유형) 으로 만 나타나는 경우에만이를 수행 할 수 있습니다 . 따라서 다음은 유효하지 않습니다.

interface I<out T>
{
  void func(T t); //Invalid variance: The type parameter 'T' must be
                  //contravariantly valid on 'I<T>.func(T)'.
                  //'T' is covariant.

}

마찬가지로으로 유형 매개 변수를 플래그하면 입력 (함수 매개 변수) in으로 만 사용할 수 있습니다 . 따라서 다음은 유효하지 않습니다.

interface I<in T>
{
  T func(); //Invalid variance: The type parameter 'T' must
            //be covariantly valid on 'I<T>.func()'. 
            //'T' is contravariant.

}

요약하면 out키워드 와의 연결 은 함수 매개 변수를 사용하면 출력 매개 변수임을 의미하고 형식 매개 변수는 형식이 출력 컨텍스트 에서만 사용된다는 것을 의미합니다 .

System.Funcrwong 이 그의 의견에서 언급 한 좋은 예이기도합니다 . 에서는 System.Func모든 입력 매개 변수를 즐겨 찾기에 추가되었습니다 아칸소 in및 출력 파라미터로 즐겨 찾기에 추가되었습니다된다 out. 그 이유는 내가 설명한 것입니다.


2
좋은 대답입니다! 저를 구해주었습니다 ... 기다립니다 ... 타이핑! 그건 그렇고 : 당신이 인용 한 LSP의 일부는 실제로 Liskov보다 오래 전에 알려졌습니다. 함수 유형에 대한 표준 서브 타이핑 규칙 일뿐입니다. (매개 변수 유형은 공변량이고 반환 유형은 공변량입니다). Liskov의 접근 방식의 새로운 규칙을 같이 분석)가이었다 없는 공동 / contravariance 측면에서하지만 대하여 행동 사전 /의 사후 조건에 의해 정의 된 대체 성 ()와 b)의 관점에서 역사 규칙 이 모든 추론을 적용하는 것을 가능하게한다, 이전에는 불가능했던 가변 데이터 유형으로
Jörg W Mittag

10

@ Gábor는 이미 연결 ( "입력"에 해당하는 모든 것에 대한 공분산, "출력"에 해당하는 모든 것에 대한 공분산)에 대해 설명했지만 키워드를 전혀 재사용하지 않는 이유는 무엇입니까?

글쎄, 키워드는 매우 비싸다. 프로그램에서 식별자로 사용할 수 없습니다. 그러나 영어에는 너무 많은 단어가 있습니다. 따라서 때로는 충돌이 발생하여 키워드와 충돌하지 않도록 변수, 메서드, 필드, 속성, 클래스, 인터페이스 또는 구조체의 이름을 어색하게 변경해야합니다. 예를 들어, 학교를 모델링하는 경우 클래스를 무엇이라고 부릅니까? class키워드 이기 때문에 클래스라고 부를 수 없습니다 !

언어에 키워드를 추가 하면 훨씬 비쌉니다. 기본적 으로이 키워드를 식별자로 사용하는 모든 코드를 불법으로 만들어 모든 곳에서 하위 호환성을 유지합니다.

inout그들은 단지 재사용 할 수 있도록 키워드는 이미 존재했다.

그들은 수있는 형식 매개 변수 목록의 컨텍스트 내에서 유일한 키워드입니다 문맥 키워드를 추가했습니다,하지만 키워드는 그들이 선택한 것? covariant그리고 contravariant? +-(스칼라 예를 들어처럼)? superextends자바처럼? 어떤 변수가 공변량 및 반 변량인지 머리 꼭대기에서 기억할 수 있습니까?

현재 솔루션에는 멋진 니모닉이 있습니다. 출력 유형 매개 변수는 out키워드를 가져오고 입력 유형 매개 변수는 in키워드를 가져옵니다 . 메소드 매개 변수와의 멋진 대칭에 유의하십시오. 출력 매개 변수는 out키워드를 가져 in오고 입력 매개 변수는 키워드를 가져옵니다 (입력이 기본값이므로 키워드는 전혀 없지만 아이디어는 얻습니다).

[참고 : 편집 히스토리를 살펴보면 실제로 원래 소개 문장에서 두 개를 바꾸 었다는 것을 알 수 있습니다. 그리고 그 기간 동안 공감대를 얻었습니다! 이것은 니모닉이 실제로 얼마나 중요한지 보여줍니다.]


공대-대-분산을 기억하는 방법은 인터페이스의 함수가 일반 인터페이스 유형의 매개 변수를 사용하는 경우 발생하는 상황을 고려하는 것입니다. 하나가있는 경우 interface Accepter<in T> { void Accept(T it);};,은 Accepter<Foo<T>>받아 들일 T경우 입력 매개 변수로 Foo<T>출력 매개 변수, 반대의 경우도 마찬가지로 받아들입니다. 따라서, 반대- 분산. 대조적으로, interface ISupplier<out T> { T get();};a는 Supplier<Foo<T>>일종의 분산의 어떤 것 Foo때문에 -이 공동 -variance을.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.