2012-11-26 4 views
4

지금까지 KeyedCollection을 사용하여 각 컬렉션의 키로 uint ID 필드가있는 1 백만 개에 가까운 많은 수의 오브젝트를 작성했습니다. 그게 좋았지 만 지금은 기능을 확장하면서 문제가 발생합니다. 레코드를 "재정의"하고 기존 항목을 새 항목으로 동일한 키로 대체해야합니다. 평균적으로 아마도 20 레코드 중 1 레코드가 동일한 레코드에 대해 여러 번 오버라이드 될 수 있습니다.교체 가능 항목이있는 키가있는 콜렉션

필요하다면 KeyedCollection에서 리팩터링 할 수 있습니다. 내 최선의 방법은 뭔가? 사전 <>? ID는 순차적이지 않으므로 곧바로 색인 생성됩니다.

+0

'사전'을 사용하십시오. 왜/어떻게 처음에'KeyedCollection'을 사용하고 있습니까? – jeroenh

+0

KeyedCollection은 기본 제공 키가있는 모델링 객체로 이동하는 방법으로 권장됩니다. 나는 지금까지 기존의 기록을 대체해야한다는 상황에 결코 빠져들지 않았으며, 그 점에 대해서는 약간 제한적이라는 것을 인식하지 못했습니다. – RobinHood70

+0

기다려라 ... 나는 사전과 함께 할 때와 마찬가지로 Remove/Add를 할 수있다. 결국 KeyedCollection에서 벗어날 필요가 없을 것입니다. – RobinHood70

답변

2

Dictionary과 마찬가지로 컬렉션에서 항목을 제거하고 바꾸거나 바꾸어 다시 추가해야합니다.

+0

확인해 주셔서 감사합니다! 긴 날이었고 나는 똑바로 생각하지 않았습니다. : -/ – RobinHood70

+0

100 % 확신하기 만하면, 내가이 일을해야한다는 것입니다. base.Remove (GetKeyForItem (anObject)); base.Add (anObject); – RenniePet

+0

@RenniePet : 아니요.'base.Remove (GetKeyForItem (desiredObject));를 수행해야합니다. ChangeState (desiredObject); base.Add (desiredObject);'. 먼저 이전 해시 코드로 객체를 제거해야합니다. 그것을 조작 (해시 코드가 변경됨)하고 다시 추가 (새 해시 코드 사용)하는 것보다. – Oliver

4

이것은 오래된 질문이며 이전에 기존 답변을 직접 사용해 보았습니다. 그러나 KeyedCollection <>을 다시 한번 들으면서, Remove-and-Then-Add 기술이 지금 구현 한 기술보다 효율적이지 않다는 것을 알게되었습니다. 문제는 Remove() 메서드가 List를 선형으로 검색 한 다음 나머지 목록을 한 항목 왼쪽으로 이동한다는 것입니다. 여기서 제시 한 기술은 List를 선형 적으로 검색하지만 적어도 List의 나머지 부분은 이동하지 않습니다.

NB. 이는 대체 항목이 교체 할 항목과 동일한 키를 가지고있는 경우에만 적용 할 수 있습니다.

/// <summary> 
    /// Derived (but still abstract) version of KeyedCollection{} to provide a couple of extra 
    /// services, in particular AddOrReplace() and Replace() methods. 
    /// </summary> 
    public abstract class KeyedList<TKey, TItem> : KeyedCollection<TKey, TItem> 
    { 
     /// <summary> 
     /// Property to provide access to the "hidden" List{} in the base class. 
     /// </summary> 
     public List<TItem> BaseList 
     { 
     get { return base.Items as List<TItem>; } 
     } 


     /// <summary> 
     /// Method to add a new object to the collection, or to replace an existing one if there is 
     /// already an object with the same key in the collection. 
     /// </summary> 
     public void AddOrReplace(TItem newObject) 
     { 
     int i = GetItemIndex(newObject); 
     if (i != -1) 
      base.SetItem(i, newObject); 
     else 
      base.Add(newObject); 
     } 


     /// <summary> 
     /// Method to replace an existing object in the collection, i.e., an object with the same key. 
     /// An exception is thrown if there is no existing object with the same key. 
     /// </summary> 
     public void Replace(TItem newObject) 
     { 
     int i = GetItemIndex(newObject); 
     if (i != -1) 
      base.SetItem(i, newObject); 
     else 
      throw new Exception("Object to be replaced not found in collection."); 
     } 


     /// <summary> 
     /// Method to get the index into the List{} in the base collection for an item that may or may 
     /// not be in the collection. Returns -1 if not found. 
     /// </summary> 
     private int GetItemIndex(TItem itemToFind) 
     { 
     TKey keyToFind = GetKeyForItem(itemToFind); 
     return BaseList.FindIndex((TItem existingItem) => 
            GetKeyForItem(existingItem).Equals(keyToFind)); 
     } 
    } 
+0

KeyedCollection의 IndexOf 메서드를 사용하여 TItem의 인덱스를 검색하는 것은 어떻습니까? –

+0

@ErwinMayer 죄송합니다. 어떻게 적용되는지 모르겠습니다. 여전히 대체 할 객체를 수정 된 AddOrReplace() 메소드의 두 번째 인수로 사용할 수 있도록해야 할 필요가 없으므로 AddOrReplace (TItem oldObject, TItem newObject)가됩니까? 그렇다면 아이디어가 더 효율적일 것입니다. 그러나 제 사용법에서는 교체 할 객체가 없습니다. 단지 맹목적으로 새로운 객체로 대체하려고합니다. – RenniePet

+0

사실, 제 구현에서 이전 키에 액세스 할 수있었습니다.그러나 나는 또한 IndexOf가 O (n)임을 알아 차렸으므로 아마도 구현보다 훨씬 효율적이지는 않을 것입니다. –