2012-03-06 3 views
5

작업 스레드에서 조작되고 DataGridView에 바인딩 된 BindingSource로 기본 UI 스레드의 BindingSource에 바인딩 된 개체를 포함하는 비동기 BindingList가 있습니다.BindingList에있는 개체 찾기

목록을 반복하지 않고도 내 BindingList에서 개체를 찾을 수 있습니까?

저는 LINQ의 두려운 부분을 살펴 봤는데 기본적으로 설탕으로 코팅 된 foreach 루프입니다. 또한 내 이해에서 IBindingList.Find()를 구현하면 for-loop 이상입니다 ...

BindingList를 미러링하고 사전을 사용하여 BindingList를 동기화/매핑하려고 "시도했습니다" 찾은 객체에 전달하고 결과 (색인)를 내 BindingList에 전달하지만 너무 많은 객체를 추가 및 제거하고 객체를 정리할 수 없기 때문에이 작업이 작동하지 않습니다.

이것은 실시간 시장의 고주파수 데이터를 처리하는 고성능 앱입니다. 그래서 BindingList를 반복 할 수 없으며 너무 비효율적입니다.

누군가가 조언이나 해결책을 제공해 줄 수 있습니까?

답변

5

빠른 검색 바인딩 목록 일종의 ... 그래서 내가 이전에 준비한 하나입니다.

참조하는 '동기화 /지도'접근 방식입니다. 나는 주요 병목 현상이 목록에서 항목을 찾는 빠른 데이터를 똑딱 거리기 위해 이것을 사용했다. 나는 동기 또는 조직적으로 유지하는 데 필요한 모든 방법을 다루었다고 믿습니다. AddRange에 대한 테스트를 추가 할 수도 있습니다. 디 컴파일러를 사용할 필요가 없습니다. InsertItem을 호출하는지 확실하지 않습니다.

명백히 두 가지 목록을 유지하면서 메모리 사용량과 삽입 시간을 늘리는 것은 직접적인 트레이드 오프입니다. 그러나 빠른 틱킹 데이터의 경우 조회 시간을 늘리기 위해 일반적으로 매우 적절한 절충안입니다.

BindingList처럼 수업을 사용하지만 항목을 빨리 찾아야하는 경우에는 FastFind 메소드를 사용하십시오.

public class FastLookupBindingList<TKey, TVal> : BindingList<TVal> 
{ 
    private readonly IDictionary<TKey, TVal> _dict = new Dictionary<TKey, TVal>(); 
    private readonly Func<TVal, TKey> _keyFunc; 

    public FastLookupBindingList(Func<TVal, TKey> keyFunc) 
    { 
     _keyFunc = keyFunc; 
    } 

    public FastLookupBindingList(Func<TVal, TKey> keyFunc, IList<TVal> sourceList) : base(sourceList) 
    { 
     _keyFunc = keyFunc; 

     foreach (var item in sourceList) 
     { 
      var key = _keyFunc(item); 
      _dict.Add(key, item); 
     } 
    } 

    public TVal FastFind(TKey key) 
    { 
     TVal val; 
     _dict.TryGetValue(key, out val); 
     return val; 
    } 

    protected override void InsertItem(int index, TVal val) 
    { 
     _dict.Add(_keyFunc(val), val); 
     base.InsertItem(index, val); 
    } 

    protected override void SetItem(int index, TVal val) 
    { 
     var key = _keyFunc(val); 
     _dict[key] = val; 

     base.SetItem(index, val); 
    } 

    protected override void RemoveItem(int index) 
    { 
     var item = this[index]; 
     var key = _keyFunc(item); 
     _dict.Remove(key); 

     base.RemoveItem(index); 
    } 

    protected override void ClearItems() 
    { 
     _dict.Clear(); 
     base.ClearItems(); 
    } 
} 

사용법 :

public class Person 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    private void simpleButton1_Click(object sender, EventArgs e) 
    { 
     var keyedBindingList = new FastLookupBindingList<int, Person>(p => p.Id) 
            { 
             new Person {Id = 1, Name = "Joe"}, 
             new Person {Id = 2, Name = "Josephine"} 
            }; 
     var person = keyedBindingList.FastFind(2); 
     var unkonwn = keyedBindingList.FastFind(4); 
    } 
+0

들으 stevenP! 나는 당신의 해결책을 보지 못했습니다. 나는 이것을 어떻게 구현하는지 이제 어떻게 작동하는지 보게 될 것이다. 그것은 좋게 보입니다. 그리고 이것은 제가 전에 시도한 것이지만 동기화를 얻을 수 없었습니다. –

+0

어떻게이 threadsafe를 만들겠습니까? backgroundthread가 인덱스 된 바인딩 목록을 업데이트하는 것과 동일한 유스 케이스가 있습니다. 그러나 구현을 사용하면 동기화 문제가 발생합니다. 어디에서나 잠금 기능을 추가하면 성능이 저하됩니다. – Rik

+0

ISynchronizeInvoke.Invoke를 사용하여 업데이트 할 수 있습니까? 즉, 백그라운드 작업자를 사용하여 데이터를 검색/조작하는 장기 실행 작업을 수행 한 다음 준비가되면 Invoke를 호출하여 UI 스레드를 가져 와서 BindingList를 업데이트합니다. –