태그 보관물: visual-studio-2008

visual-studio-2008

정적 메서드가 인스턴스 메서드를 호출하는 경우 C # 컴파일러가 오류 코드가 아닌 이유는 무엇입니까? count++;

다음 코드에는 Foo()인스턴스 메서드를 호출하는 정적 메서드가 있습니다 Bar().

public sealed class Example
{
    int count;

    public static void Foo( dynamic x )
    {
        Bar(x);
    }

    void Bar( dynamic x )
    {
        count++;
    }
}

오류 *없이 컴파일되지만 런타임에 런타임 바인더 예외가 생성됩니다. 이러한 메서드에 대한 동적 매개 변수를 제거하면 예상대로 컴파일러 오류가 발생합니다.

그렇다면 왜 동적 매개 변수가 있으면 코드를 컴파일 할 수 있습니까? ReSharper도 오류로 표시하지 않습니다.

편집 1 : * Visual Studio 2008에서

편집 2 :sealed 하위 클래스에 정적 Bar(...)메서드 가 포함될 수 있기 때문에 추가되었습니다 . 봉인 된 버전도 런타임에 인스턴스 메서드 이외의 메서드를 호출 할 수없는 경우 컴파일됩니다.



답변

업데이트 : 아래 답변은 C # 7.3 (2018 년 5 월)이 도입되기 전인 2012 년에 작성되었습니다 . 에서 C # 7.3의 새로운 기능개선 과부하 후보 , 항목 1, 오버로드 확인 규칙은 비 정적 과부하 일찍 폐기되도록 변경하는 방법을 설명합니다. 따라서 아래 답변 (및이 전체 질문)은 지금까지 대부분 역사적인 관심을 가지고 있습니다!


(C # 7.3 이전 🙂

어떤 이유로 과부하 해결 은 정적 대 비정 적을 확인 하기 전에 항상 최상의 일치 찾습니다 . 모든 정적 유형으로이 코드를 시도하십시오.

class SillyStuff
{
  static void SameName(object o) { }
  void SameName(string s) { }

  public static void Test()
  {
    SameName("Hi mom");
  }
}

최상의 오버로드는 string. 그러나 이것은 인스턴스 메소드이므로 컴파일러가 불평합니다 (두 번째로 좋은 오버로드를 취하는 대신).

덧셈 : 그래서 dynamic원래 질문 의 예에 대한 설명은 일관성을 유지하기 위해 유형이 동적 일 때 먼저 최상의 과부하를 찾는 것입니다 (정적 대 비가 아닌 매개 변수 번호 및 매개 변수 유형 등 만 확인). – 정적 ), 그런 다음 정전기 확인하십시오. 그러나 이는 정적 검사가 런타임까지 기다려야 함을 의미합니다. 따라서 관찰 된 행동.

후기 추가 :이 재미있는 순서를 선택한 이유에 대한 배경 정보는 Eric Lippert의 블로그 게시물 에서 추론 할 수 있습니다 .


답변

Foo에는 동적 인 매개 변수 “x”가 있습니다. 이는 Bar (x)가 동적 표현식임을 의미합니다.

Example은 다음과 같은 메소드를 가질 수 있습니다.

static Bar(SomeType obj)

이 경우 올바른 메서드가 해결되므로 Bar (x) 문은 완벽하게 유효합니다. 인스턴스 메서드 바 (x는)이 있다는 사실도 고려 의미도 없습니다 및되지 않습니다 : 정의 바 (X)는 동적 인 표현이기 때문에, 우리는 런타임에 해상도를 연기했다.


답변

“동적”표현식은 런타임 중에 바인딩되므로 올바른 서명 또는 인스턴스 메서드를 사용하여 정적 메서드를 정의하면 컴파일러가이를 확인하지 않습니다.

“올바른”방법은 런타임 중에 결정됩니다. 컴파일러는 런타임 동안 유효한 메서드가 있는지 알 수 없습니다.

“dynamic”키워드는 동적 및 스크립트 언어에 대해 정의되며 런타임 중에도 언제든지 Method를 정의 할 수 있습니다. 미친 물건

여기에 메서드가 인스턴스에 있기 때문에 int를 처리하지만 문자열은 처리하지 않는 샘플이 있습니다.

class Program {
    static void Main(string[] args) {
        Example.Foo(1234);
        Example.Foo("1234");
    }
}
public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}

처리 할 수없는 모든 “잘못된”호출을 처리하는 메서드를 추가 할 수 있습니다.

public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar<T>(T a) {
        Console.WriteLine("Error handling:" + a);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}


답변