[C#] 이것은 스파르타입니까?

다음은 인터뷰 질문입니다. 해결책을 찾았지만 왜 작동하는지 잘 모르겠습니다.


질문:

Sparta클래스를 수정하지 않고 MakeItReturnFalsereturn 을 만드는 코드를 작성하십시오 false.

public class Sparta : Place
{
    public bool MakeItReturnFalse()
    {
        return this is Sparta;
    }
}

내 솔루션 : (스포일러)

public class Place
{
public interface Sparta { }
}

그러나 왜 대신 SpartaMakeItReturnFalse()참조 합니까?{namespace}.Place.Sparta{namespace}.Sparta



답변

그러나 왜 대신 SpartaMakeItReturnFalse()참조 합니까?{namespace}.Place.Sparta{namespace}.Sparta

기본적으로 이름 조회 규칙이 그렇게 말하고 있기 때문입니다. C # 5 사양에서 관련 명명 규칙은 섹션 3.8 ( “네임 스페이스 및 형식 이름”)에 있습니다.

처음 몇 개의 글 머리 기호-잘리고 주석이 달린-다음과 같이 읽습니다.

  • namespace-or-type-name이 형식 I또는 형식 인 경우 I<A1, ..., AK> [이 경우 K = 0] :
    • K가 0이고 namespace-or-type-name이 제네릭 메서드 선언 내에 표시되는 경우 [nope, no generic methods]
    • 그렇지 않고 namespace-or-type-name이 형식 선언 내에 나타나면 각 인스턴스 형식 T (§10.3.1)에 대해 해당 형식 선언의 인스턴스 형식에서 시작하여 각 포함 클래스의 인스턴스 형식으로 계속됩니다. 구조체 선언 (있는 경우) :
      • 경우 K0이고 선언의 T이름의 입력 매개 변수를 포함하고 I, 그 공간 또는 타입 이름은 입력 파라미터를 지칭한다.[아니]
      • 그렇지 않으면 namespace-or-type-name이 유형 선언의 본문 내에 나타나 T 거나 기본 유형에 이름 IK유형 매개 변수 가있는 중첩 된 액세스 가능 유형이 포함 된 경우 namespace-or-type-name 은이를 참조합니다. 지정된 형식 인수로 구성된 형식입니다. [빙고!]
  • 이전 단계가 실패한 경우 각 namespace에 대해 namespace N-or-type-name이 발생하는 네임 스페이스 로 시작하여 각 엔 클로징 네임 스페이스 (있는 경우)에서 계속하고 전역 네임 스페이스로 끝나는 다음 단계가 평가됩니다. 엔티티를 찾을 때까지 :
    • 경우 K0이고 I있는 네임 스페이스의 이름입니다 N, 다음 … [예, 그 것이다 성공]

따라서 마지막 글 머리 기호 는 첫 번째 글 머리 기호가 아무것도 찾지 못하면 Sparta 클래스를 선택하는 것입니다 …하지만 기본 클래스 Place가 인터페이스를 정의 할 때 우리가 고려 하기 전에Sparta 발견 됩니다.Sparta 클래스를 .

중첩 유형을 Place.Sparta인터페이스가 아닌 클래스로 만들면 여전히 컴파일되고 반환 false되지만 컴파일러 Sparta는의 인스턴스가 클래스 의 인스턴스가 될 수 없음을 알고 있기 때문에 경고를 발행합니다 Place.Sparta. 마찬가지로 Place.Sparta인터페이스 를 유지 하지만 Sparta클래스 sealed를 만들면 Sparta인스턴스가 인터페이스를 구현할 수 없기 때문에 경고가 표시 됩니다.


답변

이름을 값으로 해석 할 때 정의의 “가까움”은 모호성을 해결하는 데 사용됩니다. “가장 가까운”정의가 무엇이든 선택됩니다.

인터페이스 Sparta는 기본 클래스 내에서 정의됩니다. 클래스 Sparta는 포함하는 네임 스페이스에 정의됩니다. 기본 클래스 내에 정의 된 것은 동일한 네임 스페이스에 정의 된 것보다 “가까이”있습니다.


답변

아름다운 질문! 매일 C #을 수행하지 않는 사람들을 위해 약간 더 긴 설명을 추가하고 싶습니다. 질문은 일반적으로 이름 확인 문제를 상기시키는 좋은 질문이기 때문입니다.

다음과 같이 약간 수정 된 원본 코드를 가져옵니다.

  • 원래 표현식에서와 같이 비교하는 대신 유형 이름을 인쇄 해 봅시다 (예 : return this is Sparta .
  • 인터페이스 Athena를 정의하겠습니다 .Place인터페이스 이름 확인을 설명하기 수퍼 클래스 .
  • 모든 것을 매우 명확하게 만들기 위해 클래스에 this바인딩 된 형식 이름을 인쇄 해 보겠습니다 Sparta.

코드는 다음과 같습니다.

public class Place {
    public interface Athena { }
}

public class Sparta : Place
{
    public void printTypeOfThis()
    {
        Console.WriteLine (this.GetType().Name);
    }

    public void printTypeOfSparta()
    {
        Console.WriteLine (typeof(Sparta));
    }

    public void printTypeOfAthena()
    {
        Console.WriteLine (typeof(Athena));
    }
}

이제 Sparta개체를 만들고 세 가지 메서드를 호출합니다.

public static void Main(string[] args)
    {
        Sparta s = new Sparta();
        s.printTypeOfThis();
        s.printTypeOfSparta();
        s.printTypeOfAthena();
    }
}

우리가 얻는 출력은 다음과 같습니다.

Sparta
Athena
Place+Athena

그러나 Place 클래스를 수정하고 Sparta 인터페이스를 정의하면 :

   public class Place {
        public interface Athena { }
        public interface Sparta { }
    }

그러면 Sparta이름 조회 메커니즘에서 먼저 사용할 수있는 인터페이스 인 인터페이스 가 다음 과 같이 변경됩니다.

Sparta
Place+Sparta
Place+Athena

그래서 우리는 MakeItReturnFalse이름 확인에 의해 처음 발견되는 슈퍼 클래스에서 Sparta 인터페이스를 정의하는 것만으로 함수 정의 에서 유형 비교를 효과적으로 엉망으로 만들었습니다.

그러나 C #은 이름 확인에서 슈퍼 클래스에 정의 된 인터페이스의 우선 순위를 지정하는 이유는 무엇입니까? @JonSkeet 알고 있습니다! 그의 답변을 읽으면 C #의 이름 확인 프로토콜에 대한 세부 정보를 얻을 수 있습니다.


답변