2012-10-19 1 views
2

우리는 매우 오래된 코드 기반을 가지고 있습니다 (실제로는 끔찍한 품질이 아닙니다). 닷넷이 시험판으로 발매 될 때까지 거슬러 올라간다. 의심 스럽지만 이상한 컨벤션의 원인이다.IEnumerator 속성을 IList <T> 또는 유사하게 리팩터링하는 데 도움이되는 도구가 있습니까?

어쨌든 .Net 1.1 지원을 중단하기 시작했고 일을 generics로 변환하고 Linq 및 모든 재미있는 것을 사용하여 건재한 하루를 보내고 있습니다. 우리의 코드베이스에서 가장 짜증나는 패턴 중 하나는 비록 우리가

private ArrayList mylist; 
public IEnumerator MyList 
{ 
    get 
    { 
    if(mylist==null) 
     return new EmptyEnumerator.Enumerator; 
    return mylist.GetEnumerator(); 
    } 
} 

이 패턴처럼 뭔가를해야하다이있는 IEnumerator는 IEnumerable을 구현하지 않기 때문에 단순히 foreach(var item in MyList) 일에서 우리를 방지하기 때문에 특히 끔찍한입니다. 대신에 우리는 다음과 같은 일을 수행해야합니다

IEnumerator enumerator=MyList; 
while(enumerator.MoveNext()) 
{ 
    object item=enumerator.Current; 
} 

그래서, 리팩토링에 대한, 물론 우리가 ReadOnlyCollection<T> 또는 IList<T> 또는 이와 유사한 같은 것을 사용하고 싶습니다. 그러나 이렇게하려면, 우리가해야 할 MyList마다 하나의 참조를 업데이트 할 수 있습니다

IEnumerator enumerator=MyList; 

어떤 경우에는

IEnumerator enumerator=MyList.GetEnumerator(); 

에, 우리는 하나 개의 속성에 백 참조를 통해 할 수 있습니다. 이것을 쉽게 할 수있는 도구가 있습니까? 우리는 최근에 Resharper를 가지고 있지만 (이 문제는 아니지만 일반적으로 사용하기 위해),이 유형의 시나리오를 다루지는 않습니다. 당신이해야 할 것처럼 들리

+2

'GetEnumerator() '를 수동으로 호출하는 대신 * 사용 *을 수정하지 않는 이유는 무엇입니까? 어쨌든 대부분의 사람들이'foreach' 루프가 될 것이라고 예상 할 수 있습니다. –

+0

모든 .cs 파일을 읽고 패턴을 찾거나 바꿀 수있는 빠른 스크립트를 작성하거나 정규 표현식을 사용할 수있을 정도로 일관성이 있습니까? –

+0

@JonSkeet 우리는 사랑하고 싶지만 작업에 헌신 할 달이 없다는 것을 알았습니다. :) 이제 우리의 계획은 근본 원인을 수정하여 새로운 코드를 작성하고 이전 코드를 수정할 수있게하는 것입니다. 그것을 통해 올 – Earlz

답변

4

모두 IEnumeratorIEnumerable<T>

를 구현하는 클래스를 돌려주고 그것의 실제로 그 하드 만이 수행 자신의 종류로 만들려면 : 대신 이제

public class MessedUpIterator<T> : IEnumerable<T>, IEnumerator 
{ 
    private IEnumerable<T> source; 
    private IEnumerator enumerator; 

    private IEnumerator MyEnumerator 
    { 
     get 
     { 
      return enumerator ?? source.GetEnumerator(); 
     } 
    } 

    public MessedUpIterator(IEnumerable<T> source) 
    { 
     this.source = source; 
    } 
    public IEnumerator<T> GetEnumerator() 
    { 
     return source.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return source.GetEnumerator(); 
    } 

    object IEnumerator.Current 
    { 
     get { return MyEnumerator.Current; } 
    } 

    bool IEnumerator.MoveNext() 
    { 
     return MyEnumerator.MoveNext(); 
    } 

    void IEnumerator.Reset() 
    { 
     MyEnumerator.Reset(); 
    } 
} 

을 반환하는 경우IEnumerator 또는 IEnumerable<T>모두을 반환 할 수 있습니다. IEnumerable<T>가 암시 적으로 구현하는 중 IEnumerable로 사용 장려 있도록 여전히 IEnumerator으로 사용하게하면서 IEnumerator이 명시 적으로 구현되는 것을

참고.

예,보기 흉하지만 확실히 악화 될 수 있습니다.

+0

우리는 코드를 더 잘 만들려고 노력하고 있습니다. 또한 코드 조각에 IEnumerable 대신 추가 기능이 필요하기 때문에 IList와 같은 것을 허용하기로 결정한 경우이 솔루션은 – Earlz

+0

@Earlz를 사용합니다. IList 및을 구현 한 클래스를 만드는 것은 쉽습니다. 'IEnumerator'. 'IList '는'IEnumerable '을 확장하기 때문에 꽤 사소한 변화가 될 것입니다; 대부분 내부적으로 저장된 'IList'에 대한 메소드를 호출하는 각 'IList'메소드에 대한 스텁을 작성합니다. 해킹 된 것처럼, 당신은 호출자 코드가 변경되지 않도록 지정함으로써 실제 문제를 해결했습니다. – Servy

+0

발신자 코드는 크게 변경하지 않고 변경할 수 있습니다. 그래서 왜 내가 .GetEnumerator()를 속성의 각 참조에 자동으로 추가 할 수있는 방법을 찾고 있었 는가? – Earlz

관련 문제