이 수업이 있습니다
public class Overloaded
{
public void ComplexOverloadResolution(params string[] something)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
}
이렇게 부르면 :
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
Normal Winner
콘솔에 기록 합니다.
그러나 다른 방법을 추가하면 :
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
다음과 같은 오류가 발생합니다.
다음 메서드 또는 속성 간의 호출이 모호합니다.> ‘
Overloaded.ComplexOverloadResolution(params string[])
‘및 ‘Overloaded.ComplexOverloadResolution<string>(string)
‘
메서드를 추가하면 호출 모호성이 발생할 수 있지만 이미 존재하는 두 메서드 (params string[])
와 <string>(string)
! 첫 번째는 매개 변수이고 두 번째는 제네릭이기 때문에 모호성과 관련된 두 가지 방법 중 어느 것도 새로 추가 된 방법이 아닙니다.
이것은 버그입니까? 사양의 어떤 부분이 이것이 사실이어야한다고 말합니까?
답변
이것은 버그입니까?
예.
축하합니다. 과부하 해결에서 버그를 발견했습니다. 버그는 C # 4 및 5에서 재현됩니다. 의미 분석기의 “Roslyn”버전에서는 재현되지 않습니다. C # 5 테스트 팀에 알 렸으며 최종 릴리스 전에이 문제를 조사하고 해결할 수 있기를 바랍니다. (항상 그렇듯이 약속은 없습니다.)
올바른 분석이 이어집니다. 후보자는 다음과 같습니다.
0: C(params string[]) in its normal form
1: C(params string[]) in its expanded form
2: C<string>(string)
3: C(string, object)
후보 0은로 string
변환 할 수 없기 때문에 분명히 적용 할 수 없습니다 string[]
. 3 개 남았습니다.
세 가지 중 고유 한 최선의 방법을 결정해야합니다. 나머지 세 후보를 쌍으로 비교하여이를 수행합니다. 그러한 세 쌍이 있습니다. 생략 된 선택적 매개 변수를 제거 하면 모두 동일한 매개 변수 목록을 가지므로 사양의 섹션 7.5.3.2에 설명 된 고급 타이 브레이킹 라운드로 이동해야합니다.
어느 쪽이 더 낫습니까, 1 또는 2? 관련 순위 결정자는 제네릭 메서드가 항상 비 제네릭 메서드보다 나쁘다는 것입니다. 2는 1보다 나쁩니다. 따라서 2는 승자가 될 수 없습니다.
1 또는 3 중 어느 것이 더 낫습니까? 관련 순위 결정자는 다음과 같습니다. 확장 된 형태로만 적용 할 수있는 방법은 항상 일반 형태로 적용 할 수있는 방법보다 나쁩니다. 따라서 1은 3보다 나쁩니다. 따라서 1이 승자가 될 수 없습니다.
2 개 또는 3 개 중 어느 것이 더 낫습니까? 관련 순위 결정자는 제네릭 메서드가 항상 비 제네릭 메서드보다 나쁘다는 것입니다. 2는 3보다 나쁩니다. 따라서 2는 승자가 될 수 없습니다.
여러 적용 가능한 후보자 세트에서 선택 되려면 후보자는 (1) 무패, (2) 적어도 한 명의 다른 후보를 이기고, (3) 처음 두 가지 속성을 가진 고유 한 후보 여야합니다. 후보 3은 다른 후보에 의해 구타를 당하지 않고 적어도 한 명의 다른 후보를 이깁니다. 이 속성을 가진 유일한 후보입니다. 따라서 후보 3은 고유 한 최상의 후보 입니다. 이길 것입니다.
C # 4 컴파일러가 잘못된 오류 메시지를 표시 할뿐만 아니라 기괴한 오류 메시지를보고하고 있음을 올바르게 알 수 있습니다. 컴파일러가 과부하 해결 분석을 잘못 받고 있다는 것은 조금 놀랍습니다. 오류 메시지가 잘못 표시되는 것은 전혀 놀라운 일이 아닙니다. “모호한 방법”오류 휴리스틱은 기본적으로 최상의 방법을 결정할 수없는 경우 후보 집합에서 두 가지 방법을 선택합니다. “실제”모호함을 찾는 데는 그다지 좋지 않습니다.
그 이유를 합리적으로 물을 수 있습니다. 찾기가 매우 까다 롭습니다 둘 은 “betterness”관계이기 때문에 “unambigously 모호한”있는 방법을 자동사 . 후보 1이 2보다 낫고, 2가 3보다 낫고, 3이 1보다 낫다는 상황을 생각 해낼 수 있습니다. 그런 상황에서 우리는 그들 중 두 개를 “모호한 것”으로 선택하는 것보다 더 잘할 수 없습니다.
Roslyn에 대한이 휴리스틱을 개선하고 싶지만 우선 순위가 낮습니다.
(독자에게 연습하십시오. “선형 시간 알고리즘을 개발하여 더 나은 관계가 전 이적이지 않은 n 개의 요소 집합에서 고유 한 최상의 멤버를 식별하십시오”는이 팀을 위해 인터뷰 한 날 제가받은 질문 중 하나였습니다. 매우 어려운 알고리즘입니다. 한번 시도해보세요.)
C #에 선택적 인수를 추가하는 것을 너무 오랫동안 밀어 붙인 이유 중 하나는 과부하 해결 알고리즘에 도입되는 복잡한 모호한 상황의 수가 많기 때문입니다. 분명히 우리는 그것을 제대로 이해하지 못했습니다.
연결 문제를 입력하여 추적하고 싶다면 부담없이 사용하십시오. 우리의 관심을 끌고 싶다면 완료 한 것으로 간주하십시오. 내년에 테스트를 진행하겠습니다.
관심을 가져 주셔서 감사합니다. 오류에 대해 사과드립니다.
답변
사양의 어떤 부분이 이것이 사실이어야한다고 말합니까?
섹션 7.4 (멤버 조회) 및 7.5.2 (유형 유추)와 함께 섹션 7.5.3 (오버로드 해결).
특히 섹션 7.5.3.2 (더 나은 함수 멤버)에는 부분적으로 “해당 인수가없는 선택적 매개 변수가 매개 변수 목록에서 제거됩니다.”라는 내용과 “M (p)가 제네릭이 아닌 메소드 인 경우 amd M (q)가 일반적인 방법이라면 M (p)가 M (q)보다 낫습니다. “
그러나 사양의 어느 부분이이 동작을 제어하는지 알 수있을만큼 사양의 이러한 부분을 충분히 이해하지 못하며 준수 여부를 판단 할 수는 없습니다.
답변
일부 메소드에서 첫 번째 매개 변수의 이름을 변경하고 할당하려는 매개 변수를 지정하여 이러한 모호함을 피할 수 있습니다.
이렇게 :
public class Overloaded
{
public void ComplexOverloadResolution(params string[] somethings)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
}
class Program
{
static void Main(string[] args)
{
Overloaded a = new Overloaded();
a.ComplexOverloadResolution(something:"asd");
}
}
답변
params
첫 번째 방법에서 를 제거하면 이런 일이 발생하지 않습니다. 첫 번째와 세 번째 방법은 모두 유효한 호출을 가지고 ComplexOverloadResolution(string)
있지만 첫 번째 방법이public void ComplexOverloadResolution(string[] something)
모호성이 없습니다.
매개 변수 값 제공 object somethingElse = null
하면 선택적인 매개 변수가되므로 해당 오버로드를 호출 할 때 지정할 필요가 없습니다.
편집 : 컴파일러는 여기에서 미친 짓을하고 있습니다. 첫 번째 메서드 이후에 코드에서 세 번째 메서드를 이동하면 올바르게보고됩니다. 따라서 올바른 항목을 확인하지 않고 처음 두 개의 과부하를 가져와보고하는 것 같습니다.
‘ConsoleApplication1.Program.ComplexOverloadResolution (params string [])’및 ‘ConsoleApplication1.Program.ComplexOverloadResolution (string, object)’
Edit2 : 새로운 발견. 위의 세 가지 방법을 제거하면 둘 사이에 모호성이 생성되지 않습니다. 따라서 순서에 관계없이 세 가지 방법이있는 경우에만 충돌이 나타나는 것 같습니다.
답변
-
쓰면
var blah = new Overloaded(); blah.ComplexOverloadResolution("Which wins?");
또는 그냥 쓰세요
var blah = new Overloaded(); blah.ComplexOverloadResolution();
윌 끝 과 동일한 방법에 있어서의,
public void ComplexOverloadResolution(params string[] something
이것은 매개 변수가 지정되지 않은
params
경우에도 가장 잘 일치하는 원인 키워드입니다. -
이렇게 새로운 방법을 추가하려고한다면
public void ComplexOverloadResolution(string something) { Console.WriteLine("Added Later"); }
매개 변수 가있는 호출과 완벽하게 일치하므로이 메소드를 완벽하게 컴파일하고 호출합니다
string
. 다음 훨씬 더 강해params string[] something
. -
두 번째 방법을 선언합니다.
public void ComplexOverloadResolution(string something, object something=null);
컴파일러, 첫 번째 방법과 이것 사이에 완전히 혼란스러워서 방금 추가했습니다. 그가 지금 당신의 전화에 어떤 기능을해야하는지 알지 못 하거든
var blah = new Overloaded(); blah.ComplexOverloadResolution("Which wins?");
실제로 다음 코드와 같이 호출에서 문자열 매개 변수를 제거하면 모든 것이 올바르게 컴파일되고 이전처럼 작동합니다.
var blah = new Overloaded(); blah.ComplexOverloadResolution(); // will be ComplexOverloadResolution(params string[] something) function called here, like a best match.
답변
