2010-07-23 4 views
1

저는 종종이 문제에 직면했습니다. 키가 단순한 숫자 ID이고 값이 객체 인 사전이 있습니다. ID는 해당 값 객체의 특정 속성에도 포함됩니다.사전 <K,V>은 IList를 구현합니다. <V>

는 다음, 나는처럼 보이는 일부 (포맷 유연성) XML 직렬화 할 수 있도록하려면 :

<listitem> 
    <id>20359</id> 
    <someotherval>foo</someotherval> 
</listitem> 
<listitem> 
    ... 

이것은 List<V>와 역 직렬화 나에게 요구를하고, 수동에 그것을 변환해야하는 불편 a Dictionary<K,V>.

두 번째 문제는 바인딩 때문입니다. 바인딩 목록을 사용하려면 소스가 ICollection (올바르게 기억하는 경우)을 구현해야하며 다시 List<V>을 수동으로 만들어 Dictionary<K,V>에서 채워야합니다.

public abstract class Keyed<KeyType> 
{ 
public KeyType key { get; set; } 
} 

public class KeyedDictionary<KeyType, ValueType> : 
Dictionary<KeyType, ValueType> 
where ValueType : Keyed<KeyType> 
{ 
// ... 
} 

public class KeyedList<KeyType, ValueType> : 
IList<ValueType>, 
System.Collections.IList 
where ValueType : Keyed<KeyType> 
{ 
public readonly KeyedDictionary<KeyType, ValueType> dict = 
    new KeyedDictionary<KeyType, ValueType>(); 

// ... 
} 

이 작동하지만, 내부적으로 크고 추한 :

나의 현재, 매우 추악한하지만 기능적인 솔루션은 다음과 같은 수업을하는 것입니다. 더 좋은 방법이 있습니까?


편집 : 여기에 해결 방법이 있습니다.

public interface IKeyed<KeyType> 
{ 
    KeyType Key { get; } 
} 

public class KeyedList<KeyType, ValueType> : 
    KeyedCollection<KeyType, ValueType> 
    where ValueType : IKeyed<KeyType> 
{ 
    protected override KeyType GetKeyForItem(ValueType item) { return item.Key; } 
} 
+0

사실 저에게는 꽤 좋은 것처럼 보입니다. 요구 사항을 충족하며 단순한 제네릭 및 인터페이스를 제공합니다. –

+0

질문이 C# 프로그래밍 언어에 관한 것이 아니라면 "C#"을 제목에서 제외하십시오. 이 질문은 C#에 관한 것이 아니라 .NET에 관한 것입니다. C#은 .NET을 사용할 수 있도록 작성한 언어입니다. –

답변

3

KeyedCollection<K,I> 유형의 소리가 트릭을 수행 할 수 있습니다. 그것은 추상적 인 클래스이므로 자신 만의 구체적인 서브 클래스를 파생시킬 필요가 있습니다.

정확한 요구에 맞는 별도의 구현을 만들 수도 있고 키 선택기 대리자를 생성자 인수로 허용하는 단일 범용 버전을 만들 수도 있습니다. (범용 버전으로 인해 대리자 호출 키 조회가있을 때마다 비용에 특화된 버전보다 소폭 덜 효율적이 될 것입니다.)

var myKeyedByIdCollection = 
    new ProjectionKeyedCollection<int, MyCustomType>(i => i.Id); 

// ... 

public class ProjectionKeyedCollection<TKey, TItem> 
    : KeyedCollection<TKey, TItem> 
{ 
    private readonly Func<TItem, TKey> _keySelector; 

    public ProjectionKeyedCollection(Func<TItem, TKey> keySelector) 
    { 
     if (keySelector == null) 
      throw new ArgumentNullException("keySelector"); 

     _keySelector = keySelector; 
    } 

    protected override TKey GetKeyForItem(TItem item) 
    { 
     return _keySelector(item); 
    } 
} 
+1

한 가지를 제외하면 좋은 대답입니다.이 generic 컬렉션은 매개 변수가없는 생성자가 없기 때문에 XML로 직렬화 할 수는 있지만 직렬화 할 수는 없습니다. 이를 해결할 수있는 두 가지 옵션은 다음과 같습니다. 1. 컬렉션을 초기화하는 클래스에 컬렉션을 래핑합니다. 2. 매개 변수없는 생성자를 제공하는 클래스의 특수 버전을 생성하십시오. –

+0

감사합니다! 1 년 전에 KeyedCollection에 대해 알고 싶었습니다! 내 구현을 질문에 붙여 넣을 것이다. – Reinderien

0

무엇에 대해 단지에 .ToDictionary()을 사용하여 다음 List<something>에 직렬화를 해제하고 그 목록? 그건 너무 불편하지 않은 것 같습니다.

+0

그것은 이상적이지 않다. 왜냐하면 사전에 어떤 연산을 한 후에는 바인딩이나 직렬화를하기 위해 reverse .ToList()를해야 할 것이기 때문이다. 이상적으로 사전과 목록을 동기화 된 상태로 유지해야하는 대신 하나의 동일한 객체가 될 것입니다. – Reinderien

관련 문제