2010-07-09 5 views
1

Google에서 너무 쉽게 질문하는 것처럼 느껴집니다. 내 자신의 버전을 구현하려고 할 때 세부 사항에 빠지기를 바랍니다. 내가 뭘하려는 건 내 데이터 유형 개체에 따라 다른 검색 기능을 사용해야 MyClass 개체 목록을 정렬하는 것입니다.IComparer <>를 위임 함수와 함께 사용하여 검색

나는 클래스 데이터 유형에 대한 마음에서이 같은 했어 :

class Datatype { 
    public delegate int CMPFN(object x, object y); 
    private CMPFN compareFunction; 

    (...) 

    private XsdDatatype((...), CMPFN compareFunction) { 
     (...) 
     this.compareFunction = compareFunction; 
    } 

    public CMPFN GetCompareFunction() { 
    return this.compareFunction; 
    } 

    static private int SortStrings(object a, object b) { 
     return ((MyClass)a).GetValue().CompareTo(((MyClass)b).GetValue()); 
    } 
} 

을 그리고 나중에 나는이 같은 MyClass에 목록 뭔가 정렬하려고 해요 :

List<MyClass> elements = GetElements(); 
Datatype datatype = new Datatype((...), Datatype.SortStrings); 
elements.Sort(datatype.GetCompareFunction()); // <-- Compile error! 

나 '를 Datatype.SortStrings에서 캐스트에 지나치게 흥분하지는 않지만이 방법이 효과가 있다고 느낍니다 (?). 그러나 컴파일러는 동의하지 않으며 위의 마지막 줄에서이 오류를 발생시키고 CMPFN을 IComparer로 변환/캐스팅 (?) 할 수없는 이유를 정확히 알지 못합니다.

Cannot convert type 'proj.Datatype.CMPFN' to 'System.Collections.Generic.IComparer<proj.MyClass>' 

답변

7

대표단은 이와 같이 오리 형식이 아닙니다. CMPFN에서으로 Comparison<MyClass>을 만들 수 있지만 일반 참조 변환은 암시 적 또는 명시 적으로 사용할 수 없습니다.

세 가지 옵션 :

  • 이 같은 비교자를 만듭니다

    elements.Sort(new Comparison<MyClass>(datatype.GetCompareFunction())); 
    
  • 사용 람다 식을 그 대신 Comparison<T> 및 사용을 만들 :

    elements.Sort((x, y) => datatype.GetCompareFunction()(x, y)); 
    
  • 쓰기 어느 쪽의 단위가 IComparer<MyClass>의 구현인가 CMPFN

주에 비교를 기반으로 형성하는 두 번째 방법은 비교에 한 번 GetCompareFunction를 호출 할 것이다.

많이 더 좋은 해결책은 CMPFN을 완전히 없애는 것입니다 - IComparer<MyClass>을 (를) 사용하는 이유는 무엇입니까? 캐스트가 제거 될 수도 있습니다. (대신 인터페이스의 위임을 사용하는 행복해서, 당신은 대신 Comparison<MyClass>과 비교를 표현할 수 있습니다.) .NET 4.5로, 당신은 Comparison<T> 대표에서 Comparer<T>를 만들 Comparer.Create를 사용할 수있는

참고.

현재 API가 object과 관련되어있는 이유를 모르겠지만 C# 3 이하 (또는 C# 4를 .NET 3.5 이하로 타겟팅)에서는 을 IComparer<MyClass>으로 변환합니다 (어쨌든 참조 변환을 통해). C# 4부터 일반적인 반항성 때문에 할 수 있습니다.당신이 원하는 것처럼 당신이

List<AttributeClass> listWithObj .... 

listWithObj.Sort(new AttributeSort()); 

처럼 다음을 호출 할 수 있습니다이

class AttributeSort : IComparer<AttributeClass > 
    { 
     #region IComparer Members 

     public int Compare(AttributeClass x, AttributeClass y) 
     {     
      if (x == null || y == null) 
       throw new ArgumentException("At least one argument is null"); 

      if (x.attributeNo == y.attributeNo) return 0; 
      if (x.attributeNo < y.attributeNo) return -1; 
      return 1; 
     } 

     #endregion 
    } 

같은

+1

을 ... 확실히 당신이하지''IComparer'을 new' 수 있습니까? –

+0

@ 리차드 : 나쁘다. 나는 위임 된 땅에서 머리를 터뜨 렸습니다. 편집 할 것입니다. 분명히 너무 이른 것 같습니다 :) –

+0

[컴파일러가 사과했는지] (http://meta.stackexchange.com/questions/9134/jon-skeet-facts), 궁금합니다. –

1

시도 뭔가 작업을해야합니다. 형식 안전 비교 클래스도 만들 수 있습니다.

+0

제네릭이 부족한 이유는 무엇입니까? OP는 분명히 원래 코드에서 제네릭을 사용하고 있기 때문에'ArrayList'와 비 인터랙티브 IComparer 인터페이스로 돌아갈 호출이 보이지 않습니다. –

+0

내 잘못이야, 일찍했고 (그리고 어쩌면 오래된) 코드가 완료되었습니다. :)하지만 그것은 일반 버전은별로 다르지 않습니다. – HerrVoennchen

1

많은 오버로드가 List<T>.Sort이지만 사용자가 정의한 매개 변수 (두 개의 개체)를 사용하여 위임을받는 것은 없습니다.

그러나 약간의 수정 작업으로 코드 작업을 수행 할 수있는 오버로드가 Comparison<T> 인 대리자가 있습니다. 기본적으로, 당신은 단지 Comparison<MyClass>으로 CMPFN 대리자를 교체 - 추가 보너스로, 당신은 당신의 SortStrings 기능에 강한 입력을 얻을, 너무 :

static private int SortStrings(MyClass a, MyClass b) { 
    return a.GetValue().CompareTo(b.GetValue()); 
} 

public Comparison<MyClass> GetCompareFunction() { 
    return SortStrings; // or whatever 
} 

... 

elements.Sort(datatype.GetCompareFunction()); 
관련 문제