하위 수준 호출자가 C# 4.0으로 생성된 어셈블리의 선택적 매개 변수를 활용할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/983152

  •  13-09-2019
  •  | 
  •  

문제

기존 어셈블리가 있고 일부 클래스에 오버로드된 메서드가 있고 해당 오버로드 중 일부에 대해 기본 동작이나 값이 가정되어 있다고 가정해 보겠습니다.나는 이것이 매우 전형적인 패턴이라고 생각합니다.

Type2 _defaultValueForParam2 = foo;
Type3 _defaultValueForParam3 = bar;

public ReturnType TheMethod(Type1 param1)
{
   return TheMethod(param1, _defaultValueForParam2);
}
public ReturnType TheMethod(Type1 param1, Type2 param2)
{
   return TheMethod(param1, param2, _defaultValueForParam3);
}
public ReturnType TheMethod(Type1 param1, Type2 param2, Type3 param3)
{
   // actually implement the method here. 
}

그리고 C#의 선택적 매개변수를 사용하면 이를 단일 메서드로 통합할 수 있다는 것을 알고 있습니다.선택 사항으로 표시된 일부 매개변수를 사용하여 메서드를 생성하면 어셈블리의 하위 수준 호출자와 함께 작동합니까?


편집하다:"일"이란 내 말은, 하위 호출자, C# 2.0 또는 3.5 컴파일러로 컴파일된 앱인 는 마치 오버로드를 사용한 것처럼 매개변수 1개, 2개 또는 3개를 사용하여 메서드를 호출할 수 있으며 하위 수준 컴파일러는 불평하지 않습니다.

내 라이브러리의 모든 오버로드를 리팩터링하고 제거하고 싶지만 리팩터링된 라이브러리를 사용하는 하위 호출자가 모든 매개변수를 제공하도록 강요하고 싶지는 않습니다.

도움이 되었습니까?

해결책

나는 새로운 언어 표준에 관한 문서를 읽지 않았지만 4.0 이전 버전의 호출자는 이 문서를 통과해야 할 것이라고 생각합니다. 모두 지금과 마찬가지로 매개변수를 선언했습니다.이는 매개변수 전달이 작동하는 방식 때문입니다.

메서드를 호출하면 인수가 스택에 푸시됩니다.세 개의 32비트 인수가 전달되면 12바이트가 스택에 푸시됩니다.4개의 32비트 인수가 전달되면 16바이트가 스택에 푸시됩니다.스택에 푸시된 바이트 수는 호출에 내재되어 있습니다.호출 수신자는 올바른 수의 인수가 전달되었다고 가정합니다.

따라서 함수가 4개의 32비트 매개변수를 사용하는 경우 호출자의 반환 주소 앞의 16바이트에서 스택을 찾습니다.호출자가 12바이트만 전달한 경우 호출 수신자는 호출이 이루어지기 전에 이미 스택에 있던 내용 중 4바이트를 읽습니다.예상되는 16바이트가 모두 전달되지 않았음을 알 수 있는 방법이 없습니다.

이것이 지금 작동하는 방식입니다.기존 컴파일러에서는 변경 사항이 없습니다.

선택적 매개변수를 지원하려면 다음 두 가지 중 하나가 발생해야 합니다.

  1. 호출자는 스택에 푸시된 인수(또는 바이트) 수를 호출 수신자에게 명시적으로 알려주는 추가 값을 전달할 수 있습니다.그런 다음 호출 수신자는 생략된 매개변수에 대한 기본값을 채울 수 있습니다.
  2. 호출자는 코드에서 생략된 선택적 매개변수를 기본값(호출자의 메타데이터에서 읽음)으로 대체하여 선언된 모든 매개변수를 계속 전달할 수 있습니다.그러면 호출 수신자는 지금과 마찬가지로 스택에서 모든 매개변수 값을 읽습니다.

위의 (2)와 같이 구현될 것으로 예상됩니다.이는 C++에서 수행되는 방식과 유사합니다(메타데이터가 부족한 C++에서는 기본 매개변수를 헤더 파일에 지정해야 함). 옵션 (1)이 모두 컴파일 타임에 수행되고 별도의 작업을 수행하지 않기 때문에 더 효율적입니다. 스택에 푸시하려면 추가 값이 필요하며 가장 간단한 구현입니다.옵션 (2)의 단점은 기본값이 변경되면 모든 호출자를 다시 컴파일해야 하며 그렇지 않으면 상수로 컴파일되었기 때문에 이전 기본값을 계속 전달한다는 것입니다.이는 현재 공개 상수가 작동하는 방식과 유사합니다.옵션 (1)에는 이러한 단점이 없습니다.

옵션 (1)은 또한 명명된 매개변수 전달을 지원하지 않습니다. 따라서 함수가 다음과 같이 선언되면:

static void Foo(int a, int b = 0, int c = 0){}

다음과 같이 호출할 수 있습니다.

Foo(1, c: 2);

이를 허용하도록 옵션 (1)을 수정하여 추가 숨겨진 값을 생략된 인수의 비트맵으로 만들 수 있습니다. 여기서 각 비트는 하나의 선택적 매개변수를 나타냅니다.이는 함수가 허용할 수 있는 선택적 매개변수의 수를 임의로 제한합니다. 비록 이 제한이 최소한 32개라는 점을 고려하면 그렇게 나쁜 것은 아닐 수도 있습니다.그러나 이것이 실제 구현일 가능성은 매우 낮습니다.

구현이 주어지면 호출 코드는 ~ 해야 하다 호출에서 인수를 생략하기 위한 선택적 매개변수의 메커니즘을 이해합니다.또한 옵션 (1)을 사용하면 메타데이터에 형식 매개변수로 추가되지 않는 한 이전 컴파일러에서는 이를 알 수 없는 추가 숨겨진 매개변수를 전달해야 합니다.

다른 팁

C# 4.0에서 옵션 매개 변수가 생략되면 해당 매개 변수의 기본값이 대체됩니다.

public void SendMail(string toAddress, string bodyText, bool ccAdministrator = true, bool isBodyHtml = false)
{ 
    // Full implementation here   
}

다운 레벨 발신자의 경우 매개 변수가 누락 된 변형 중 하나를 사용하면 C#이 누락 된 매개 변수에 대해 제공 한 기본값을 대체하십시오.. 이 기사에서는 프로세스에 대해 자세히 설명합니다.

기존 다운 레벨 호출은 모두 여전히 작동해야하지만 C# 4.0에서 고객을 다시 컴파일해야합니다..

글쎄, 3 가지 방법을 단일 메소드로 선택한 매개 변수로 바꾸면 라이브러리를 사용하는 코드가 여전히 작동하지만 다시 컴파일해야한다고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top