Así que un tipo de lista de enlaces de búsqueda rápida ... Aquí hay uno que preparé antes.
Este es el enfoque 'sincronizar/asignar' al que se refiere. Lo he usado antes para datos rápidos, donde el cuello de botella principal buscaba elementos en la lista. Creo que he cubierto todos los métodos necesarios para mantenerme sincronizado u 'organizado'. Puede agregar una prueba para AddRange: no tengo un decompilador a mano, no estoy seguro si solo llama a InsertItem.
Obviamente, aquí tiene un compromiso directo de mayor uso de memoria e tiempo de inserción, manteniendo dos listas, pero para datos de marcación rápida, que normalmente es una solución aceptable para tiempos de búsqueda mejorados.
Utilice la clase como lo haría con un BindingList
, pero cuando necesite buscar un elemento rápidamente, utilice el método 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();
}
}
Uso:
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);
}
THX stevenP! Nunca vi tu solución. Voy a implementar esto ahora y ver cómo funciona. se ve bien sin embargo, y esto es lo que estaba intentando hacer antes, pero no pude conseguir la sincronización en su lugar. –
¿Cómo harías que este threadsafe. Tenemos el mismo caso de uso donde un hilo de fondo actualiza la lista de enlaces indexada. Sin embargo, el uso de su implementación causa problemas de sincronización. Agregar bloqueo en todas partes, perjudica el rendimiento también. – Rik
¿Se puede usar ISynchronizeInvoke.Invoke para hacer sus actualizaciones? Es decir, utilice el trabajador en segundo plano para realizar la tarea de larga ejecución de recuperar/manipular sus datos, y cuando esté listo, llame a Invoke para obtener el hilo de la interfaz de usuario y actualizar BindingList. –