2010-03-21 3 views
15

FilePathCollection을 구현하려고합니다. 그 항목은 단순한 파일 이름입니다 (예 : "image.jpg"와 같은 경로 없음). 컬렉션을 foreach주기를 통해 사용한 후에는 baseDirectory과 연결하여 생성 된 전체 경로를 반환해야합니다. 어떻게해야합니까?List에서 상속받은 컬렉션에 대해 GetEnumerator() 구현 <string>

public class FilePathCollection : List<string> 
{ 
    string baseDirectory; 

    public FilePathCollection(string baseDirectory) 
    { 
     this.baseDirectory = baseDirectory; 
    } 

    new public System.Collections.IEnumerator GetEnumerator() 
    { 
     foreach (string value in this._items) //this does not work because _list is private 
      yield return baseDirectory + value; 
    } 
} 
+5

이 사용 ... 그것을 일반적인 과부하를하시기 바랍니다주고'Path.Combine (base 디렉토리, 값)'http://msdn.microsoft.com/en-us/library/fyy7a5kt.aspx . –

답변

26
new public IEnumerator GetEnumerator() 
{ 
    using(IEnumerator ie = base.GetEnumerator()) 
    while (ie.MoveNext()) { 
     yield return Path.Combine(baseDirectory, ie.Current); 
    } 
} 
+0

브릴리언트, 그것입니다 :-) thanks – Vojtech

+5

이것은 'Enumerable.Select'의 전문적인 재 작성과 매우 흡사합니다. –

+1

Daniel, 나는 그가 선택한 접근법을 취하는 방법을 보여주었습니다. 당신은 수업을 전혀 사용하지 않는 것에 대한 좋은 주장을 가지고 있습니다. –

1

당신은 아마 사용 base.GetEnumerator() 및 수동으로 반복 할 수있다.

그러나 나는 당신이하려고하는 방식대로 클래스를 디자인하는 모든 종류의 문제에 부딪치게 될 것이라고 생각합니다. 당신은 당신이 그들에게 넣는 목록에서 같은 값을 가져야한다. 예를 들어 코드를 사용하면 인덱서를 사용할 때보 다 목록을 열거하는 값이 달라집니다. 또한 Add() 또는 Contains()와 같은 List의 다른 메소드가 무엇인지 명확하게 알 수 있습니까?

파일 이름 목록과 기본 디렉터리를 가져 와서 각 요소가 dir + file 인 새 결과 목록을 생성하는 정적 메서드를 만들 수없는 이유가 있습니까? 당신에게 다형성 문제가 발생할 수 있습니다 새로운 키워드를 사용하여

4

: 경우 일부 수행합니다

List<string> files = new FilePathCollection(); 

foreach (var files in files)를 호출하면되지 오버라이드 (override) 열거를 호출하게됩니다.

나는 최상이 IEnumerable<string>에서 상속 받고 당신의 명부를 가진 개인 분야를 보전된다고 생각한다. 이 그것을 할 수있는 방법이 될 수 예를 들어

: 당신이 C는 # 3, 당신이해야 할 특별한 클래스를 작성할 필요가 없습니다 경우 이미 IEnumerable<T>

public class FilePathCollection : IList<string> 
    { 
     string baseDirectory; 
     private List<string> internalList; 

     public FilePathCollection(string baseDirectory) 
     { 
      this.baseDirectory = baseDirectory; 
     } 

     #region IList<string> Members 

     public int IndexOf(string item) 
     { 
      return GetFileNameOnly(internalList.IndexOf(item)); 
     } 
     private string GetFileNameOnly(string p) 
     { 
      //your implementation....... 
      throw new NotImplementedException(); 
     } 

     private int GetFileNameOnly(int p) 
     { 
      //your implementation....... 
      throw new NotImplementedException(); 
     } 

     public void Insert(int index, string item) 
     { 
      internalList.Insert(index, item); 
     } 

     public void RemoveAt(int index) 
     { 
      internalList.RemoveAt(index); 
     } 

     public string this[int index] 
     { 
      get 
      { 
       return GetFileNameOnly(internalList[index]); 
      } 
      set 
      { 
       this[index] = value; 
      } 
     } 



     #endregion 

     #region ICollection<string> Members 

     public void Add(string item) 
     { 
      internalList.Add(item); 
     } 

     public void Clear() 
     { 
      internalList.Clear(); 
     } 

     public bool Contains(string item) 
     { 
      return internalList.Contains(item); 
     } 

     public void CopyTo(string[] array, int arrayIndex) 
     { 
      internalList.CopyTo(array, arrayIndex); 
     } 

     public int Count 
     { 
      get { return internalList.Count; } 
     } 

     public bool IsReadOnly 
     { 
      get { return false; } 
     } 

     public bool Remove(string item) 
     { 
      return internalList.Remove(item); 
     } 

     #endregion 

     #region IEnumerable<string> Members 

     public IEnumerator<string> GetEnumerator() 
     { 
      foreach(string value in internalList) 
       yield return baseDirectory + value; 
     } 

     #endregion 

     #region IEnumerable Members 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      foreach(string value in internalList) 
       yield return baseDirectory + value; 
     } 

     #endregion 
    } 
+1

실제로, 상속 대신에 구성. – Dykam

+3

이것은 'Enumerable.Select'를 다시 작성하는 데 오랜 기간 바람을 피 웠습니다. –

12

에서 상속하는 I List<string>에서 상속 이. 당신이 그런 IEnumerable<string>를 지원하는 List<string> 또는 string[], 아무것도 같은 문자열의 순서는, filePathCollection라는 한 가정하면, 당신은 사용할 수 있습니다

var prefixedPaths = filePathCollection.Select(path => baseDirectory + path); 

이 헤이 프레스토 - 당신은 지금 baseDirectory로 시작 경로의 IEnumerable<string>이 있으므로 당신은 foreach 등을 사용할 수 있습니다. 끝났습니다.


이 답변의 나머지 부분은 다른 경우에 적용 할 수있는 부분을 설명하는 좀 더 일반적인 설명입니다.

Select은 필수적으로 다음을 의미합니다.이 일련의 항목을 취하여 각 항목과 함께 무언가를 수행하고 모든 결과가 포함 된 새 순서를 되돌려 보냅니다. "무언가"는 이전 시퀀스에 저장된 것과 동일한 유형의 매개 변수 하나를 허용하는 메서드를 제공하여 지정되며 원하는 시퀀스를 반환합니다.이 시퀀스는 새 시퀀스의 항목 유형이됩니다. 이 경우 항목 유형이 변경되지 않습니다.당신이 연주로 path 생각할 수있는 - 그래서 pathstring이며,

path => baseDirectory + path 

컴파일러는 소스 컬렉션의 요소 유형이 string 것으로 파악 : 또한 우리는 람다를 사용하여 "대신에"방법을 정의하고 모든 것을 스스로 작성해야하는 경우 "루프 변수"와 동일한 역할을합니다. 그리고 path에 연결을 사용하므로 결과는 또 다른 string이므로 새 시퀀스도 IEnumerable<string>이어야합니다. 이것은 "형식 유추"이며이 내용이 작성해야하는 코드의 양을 줄이는 데 중요한 부분입니다.

또 다른 중요한 일은 "닫힘"입니다. 이것은 우리의 람다를 "열린"매개 변수 path뿐만 아니라 "닫힌"매개 변수 baseDirectory에도 의존하지 않는 기술적 이름입니다. 명시 적으로 매개 변수로 전달됩니다. 람다는 그저 바깥쪽에 도달하여 그 안에 정의 된 메소드의 변수를 볼 수 있습니다. 이것은 특히 baseDirectory을 매개 변수로 사용하여 _baseDirectory 필드에 저장하는 생성자를 작성해야하는 필요성을 없애기 때문에 나중에 다른 메소드에서 반복적으로 사용할 수 있습니다.

새 시퀀스는 항상 들어오는 시퀀스와 길이가 같습니다. 항목을 필터링하려면 Where을 사용하십시오. 시퀀스를 더 길게하려면 SelectMany을 사용하십시오.

+1

+1. 단순한 문제에 대한 간단한 해결책. 키스 : –

+2

로마인, 날 붉게하고있어! –

+0

+1이 짧은 해결책을 좋아했습니다. –

0

기본 유형으로 캐스트 할 수 있습니다.

new public System.Collections.IEnumerator GetEnumerator() 
{ 
    foreach (string value in (List<string>)this) //<-- note the cast 
     yield return baseDirectory + value; 
} 

이상적으로는 Select 확장 방법을 사용하는 것이 가장 이상적입니다. 그리고

무슨 일이 있어도
public new IEnumerator<string> GetEnumerator() 
{ 
    return ((List<string>)this).Select(x => baseDirectory + x).GetEnumerator(); 
} 
관련 문제