4

다음 샘플 코드가 있습니다 (C #3.5 연구 목적으로 만 사용되었습니다!).

IEnumerable 및 정렬 함수를 받아들이는 Sort 함수를 호출하고 있습니다. 내가 람다 식 (사례 A)를 사용하여 호출하면 컴파일러는 반환 형식 TResult를 파생시킬 수 있지만 func SortInt (사례 B)를 전달하면 컴파일러에서 오류가 발생합니다!

컴파일러가 두 번째 경우에서 TResult를 파생시킬 수없는 이유를 이해할 수 없습니다! 나는 똑같은 정보를 전달하는 것처럼 보인다. 아니면 정확하지 않습니까?

도와주세요 !

int[] intArray = { 1, 3, 2, 5, 1 };

IEnumerable<int> intArray2 = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

IEnumerable<int> nextIntArray = Sort(intArray, SortInt); // <= CASE B - Compile Error: Cannot Infer Type !

public static IEnumerable<TResult> Sort<T, TResult>(IEnumerable<T> toBeSorted,    
                              Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
{
    return sortFunc(toBeSorted);
}

public static IEnumerable<int> SortInt(IEnumerable<int> array)
{
    return array.OrderByDescending(x => x);
}


  • 인도인처럼 당신의 이름은 인도어입니다. - Anirudha Gupta

4 답변


6

컴파일러가 SortInt에 대한 과부하 해결을 수행 할 수 없기 때문에 두 번째 예제에서 추론이 실패하는 것처럼 보입니다.

이것은보다 철저한 설명으로서 유용 할 수 있습니다 :

http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx


  • 이 기사는 이제 다소 시대에 뒤진 것입니다. 이 기사의 피드백을 토대로 이러한 유형의 상황에 대해 형식 유추 알고리즘이 다소 개선되었습니다. - Eric Lippert
  • 즉,이 경우에도 과부하 해결 방법을 수행하지 못한 경우의 예입니다. - Eric Lippert
  • @ Robert, 감사합니다! 이 기사는 정확하게이 지점을 다루었습니다! - Preets
  • @ 에릭, 그 기사 주셔서 감사합니다! 개선 사항을 설명하는 새 기사를 작성 했습니까? 그게 좋을거야! 고마워 ! - Preets
  • 좋아, 찾았 어.blogs.msdn.com/ericlippert/archive/tags/Type+Inference/…! - Preets

5

타입 유추가 메소드 그룹 변환에 잘 작동하지 않는다는 것에 짜증납니다. C #컴파일러가 그룹에 적용 할 수있는 메소드가 하나 뿐인 일반적인 경우에 더 똑똑해지기를 바랍니다. 그러나 복잡한 상황에서는 여러 유형의 유추를 초래할 수있는 여러 가지 적용 가능한 과부하로 끝날 수 있습니다.

옵션 :

  • 표시된 것처럼 람다 식에서 메서드 호출
  • 추측에 의존하는 대신 형식 인수를 명시 적으로 지정하십시오.
  • 관련된 특정 유형으로 메소드 그룹을 변환하십시오 (두 번째 옵션보다 나쁨).
  • 별도의 지역 변수를 사용하고 그 유형을 명시 적으로 지정하십시오

기본적으로 나는 처음 두 옵션 중 하나를 고수 할 것이고 두 옵션 모두 성가신 것입니다. 추가 옵션 인 간접 참조로 인해 첫 번째 옵션에서 약간의 성능 손실이 발생하지만 대개 중요하지는 않습니다.


  • 설명해 주셔서 감사합니다. 타입 유추가 메소드 그룹에서 작동하지 않는다는 것을 알았습니다! ' 이유 ' 내게 가장 간단한 일은 아니지만! - Preets

3

IEnumerable<int> intArray = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

이 문장에서 x => SortInt (x)는 아래와 같은 델리게이트 표현입니다.

delegate(IEnumerable<int> x){
    return SortInt(x);
}

엄밀히 말하면, 명세서의 어디에서나 SortInt에 대한 참조를 전달하지 않습니다.

Func, IEnumerable>은 대리자 형식이므로 "함수 포인터"는 필요하지만 함수는 필요하지 않습니다. 다른 곳에서는, SortInt가 메소드입니다.

더 깊게 파고 들면, x => SortInt (x)의 실제 컴파일 표현은 다음과 같습니다.

private static IEnumerable<int> __XYZ(IEnumerable<int> x){
   return SortInt(x);
}

private delegate IEnumerable<int> __XYZHANDLER(IEnumerable<int> x);

그리고 1 호선은

IEnumerable<int> intArray = Sort(intArray, new __XYZHANDLER(__XYZ) );

이제 2 행을 살펴보면, SortInt는 아무 것도 아니며, 메서드 이름이고, 어떤 유형이나 인스턴스도 아닙니다. 메소드 매개 변수가 가질 수있는 것은 어떤 유형의 인스턴스입니다. new Delegate는 메서드 포인터가 아닌 메서드 포인터의 인스턴스입니다.

x => SortInt (x)는 위에 설명 된 모든 형식의 간략한 형식입니다. lamda는 일반적으로 익명의 대리자를 작성하는 작은 형식이며, 컴파일러는 SortInt를 x => SortInt (x)로 유추하지 않습니다.


0

코드에는 작동하지 못하게하는 몇 가지 문제가있었습니다.

우선, 귀하의 유형이 모두 일치하지 않았습니다. int []를 IEnumerable로 전달했지만, .AsEnumerable ()을 호출하지 않으면 그렇게 할 수 없습니다.

둘째, T와 TResult는 사용법 (int)이 같지만 컴파일러와 동일하지는 않지만 결과의 형식이 무엇인지 말하지 않고 int 배열을 전달하고 IEnumerable을 예상합니다. 따라서 TResult 형식에서 Sort (intArray.AsEnumerable (), SortInt)와 같은 버전을 전달해야하지만 TResult는 필요하지 않습니다. 동일한 형식 인 T를 주문 했으므로 필요하지 않습니다.

그래서, 나는 TResult를 없애고 타입들을 고쳤다 :

void Main() 
{
  var intArray = new [] { 1, 3, 2, 5, 1 };
  var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
  var nextInts = Sort(intArray.AsEnumerable(), SortInt); 
}

public static IEnumerable<T> Sort<T>(
              IEnumerable<T> toBeSorted, 
              Func<IEnumerable<T>, IEnumerable<T>> sortFunc) 
{        
   return sortFunc(toBeSorted);
}

public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array) 
{    
    return array.OrderByDescending(x => x);
}

나는 위의 것을 선호하지만, 이것은 내가 여러분의 샘플에 가깝게 접근 할 수있는 가장 가까운 방법입니다 :

  void Main() {
    var intArray = new [] { 1, 3, 2, 5, 1 };
    var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
    var nextInts = Sort<int, int>(intArray.AsEnumerable(), SortInt); 
   }

   public static IEnumerable<TResult> Sort<T, TResult>(
                 IEnumerable<T> toBeSorted, 
                 Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
   {    
      return sortFunc(toBeSorted);
   }
   public static IEnumerable<int> SortInt(IEnumerable<int> array){    
      return array.OrderByDescending(x => x);
   }

SortInt는 다음과 같을 수도 있습니다.

public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array){    
   return array.OrderByDescending(x => x);
}

Akash는 람다 식을 사용할 때 차이점을 설명합니다.

관련된 질문

최근 질문