2012-07-23 6 views
2

나는 사전에 목록을 저장하는 캐시 클래스가 :액세스 속성은

이제
public class CacheList<T> 
{ 
    private Dictionary<UInt64, T> _cacheItems = new Dictionary<UInt64, T>(); 

    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public void Add(T item) 
    { 
     UInt64 key = (UInt64)(item.GetHashCode()); 

     if (!_cacheItems.ContainsKey(key)) 
      _cacheItems.Add(key, item); 
    } 
} 

나는 일반 T.에서의 해시 코드를 얻어서 사전에 항목을 추가하고 그러나 나는 싶습니다 키로 갖고 싶은 필드/속성을 지정하십시오. 문제는 유형 T이므로이 항목에있는 특성을 알지 못합니다.

일반 항목에서 속성에 액세스하려면 어떻게해야합니까?

+2

이것은 해시 코드를 키로 사용해서는 안되며 (고유 한 것은 아닙니다), 'int'를 'ulong'으로 저장하는 이유는 없습니다 –

+0

왜 항목을 사전에 저장하고 키 생성에주의를 기울여야합니다. HashSet 과 같은 다른 구조를 사용하지 않는 이유는 무엇입니까? 왜냐하면 당신이 키를 생성하는 방식이기 때문에 사전에 항목을 찾을 키를 생성하기 위해 항목을 제공해야합니다. – Tamir

+0

@marc, 귀하의 의견을 주셔서 감사합니다,하지만 이것은 내 문제를 보여주기위한 간단한 테스트였습니다 :) – YesMan85

답변

2

: 다음

public class CacheList<T, TKey> 
{ 
    private readonly Dictionary<TKey, T> _cacheItems = new Dictionary<TKey, T>(); 
    private readonly Func<T, TKey> selector; 
    public CacheList(Func<T, TKey> selector) 
    { 
     this.selector = selector; 
    } 
    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public bool Add(T item) 
    { 
     TKey key = selector(item); 

     if (_cacheItems.ContainsKey(key)) { return false; } 

     _cacheItems.Add(key, item); 
     return true; 
    } 
    public bool TryGetValue(TKey key, out T value) 
    { 
     return _cacheItems.TryGetValue(key, out value); 
    } 
} 

:

var dict = new CacheList<Customer,int>(c => c.CustomerId); 
+0

+1 정말 멋지다. 변화를 위해 키가 필요하다면 인터페이스를 만드는 것에 대해 헛소리 할 필요가 없다는 것을 의미합니다. –

+0

당신은 나를 60 초도 채 안되어 똑같은 해결책으로 때렸다. Grrr. 더하기 측면에서, 그것은 아주 좋은 대답이어야합니다. ;-) – Enigmativity

+0

정확히 내가 무엇을 찾고 있었는지! – YesMan85

2

나는 제네릭을 보았고 "제약"을 생각했지만 뒤늦은 생각으로 나는 Marc's approach을 선호했다. 그래서 나는 그의 길로 갈 것이다.

당신은 그 인터페이스에 제한 후 필요한 재산 노출하는 인터페이스를 만들 수

:

interface IExposeKey 
{ 
    string Key { get; } 
} 

public class CacheList<T> where T : IExposeKey { } 

코드에서 컴파일러는 지금 T는 가정 할 수는 IExposeKey 있으므로 적절하게 강력한 형식의 액세스를 제공 할 수 있습니다 :

public void Add(T item) 
{ 
    string key = item.Key; 

    if (!_cacheItems.ContainsKey(key)) 
     _cacheItems.Add(key, item); 
} 

당신은 다음 T 인스턴스에서 반사를 사용하려면이 방법으로 속성 이름을 노출 할 수 있지만 런타임 오류에 대한 문을 엽니 다. 어쩌면

2

당신은 키를 지정하기 위해 람다 함수를 사용할 수 있습니다. 이런 식으로 뭔가 :

public class CacheList<T, P> 
{ 
    private Dictionary<P, T> _cacheItems = new Dictionary<P, T>(); 
    private Func<T, P> _getKey; 

    public CacheList(Func<T, P> getKey) 
    { 
     _getKey = getKey; 
    } 

    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public void Add(T item) 
    { 
     P key = _getKey(item); 

     if (!_cacheItems.ContainsKey(key)) 
      _cacheItems.Add(key, item); 
    } 
} 

당신은 다음과 같이 인스턴스를 만들 것입니다 :

var cl = new CacheList<MyClass, string>(x => x.SomeProperty); 

당신을 위해이 일을합니까?

+0

네, 감사합니다! 그러나 나는 TKey 때문에 Marc Gravell의 대답에 갔다. – YesMan85