There is one method which does the
searching, but that method receives the object, and the string to
search in that object and runs the FOR loop to find the answer.
... just convert the type from
List to Hashtable in this method and then quickly find it.
First: for replacing List<T>, you want to use Dictionary<string, T>,
not Hashtable (using string keys as mentioned). With this done, you
would simply have to update this method to use the dictionary methods
(indexer if you strongly believe the item is in the Dictionary;
TryGetValue if you can't be sure).
However! Changing to Dictionary will change a few things; for
instance, it won't be IEnumerable<Tany more (IIRC it is
IEnumerable<KeyValuePair<TKey,TValue>>, with separate .Keys
and .Values properties). Secondly, the sequence becomes undefined
(Dictionary does not respect insertion order).
Perhaps what you need is something that behaves like a Collection<T>
(since List<Tnot very easy to inherit), but handles an inner
Dictionary? To allow for Add(T), this would mean that the key would
have to be obtainable from the item... hmm...
How about below; is still IEnumerable<T>, etc, but you just need to
update your entities to support the Key, and your search method to use
the indexer (in your case, since no conflict between String and
Int32); if you can't add the Key, then you'd presumably need to change
the Add methods, or use some form of key-provider similar to the hash-
code provider (aka IEqualityComparer<T>).
Marc
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
static class Program
{
static void Main()
{
IndexedList<string, MyDataitems = new IndexedList<string,
MyData>();
items.Add(new MyData("Item 1"));
items.Add(new MyData("Item 2"));
items.Add(new MyData("Item 3"));
MyData item = items["Item 2"];
}
}
public class MyData : IKeyed<string>
{
// lazy fields instead of properties...
public MyData(string @ref)
{
Ref = @ref;
}
public readonly string Ref; // key should be immutable for
hashtable
public string Name;
public string AddressLine1;
public int Something;
string IKeyed<string>.Key { get { return Ref; } }
}
public interface IKeyed<T{
T Key {get;}
}
public class IndexedList<TKey, TValue: Collection<TValuewhere
TValue : IKeyed<TKey>
{
public TValue this[TKey key] {
get { return _index[key]; }
}
// "get by" for when TKey is int, which causes indexer conflict
public TValue GetByKey(TKey key)
{
return _index[key];
}
public TValue GetByIndex(int index)
{
return base[index];
}
public bool TryGetByKey(TKey key, out TValue value)
{
return _index.TryGetValue(key, out value);
}
public IndexedList(IEqualityComparer<TKeykeyComparer)
{
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
}
public IndexedList() : this(null) { }
private readonly IEqualityComparer<TKey_keyComparer;
private readonly Dictionary<TKey, TValue_index = new
Dictionary<TKey, TValue>();
protected override void InsertItem(int index, TValue item)
{
_index.Add(item.Key, item); // checks unique before adding to
either list
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
_index.Remove(this[index].Key);
base.RemoveItem(index);
}
protected override void ClearItems()
{
_index.Clear();
base.ClearItems();
}
protected override void SetItem(int index, TValue item)
{
TKey oldKey = this[index].Key, newKey = item.Key;
if (_keyComparer.Equals(oldKey, newKey))
{ // key same; update existing
_index[newKey] = item;
}
else if (_index.ContainsKey(newKey))
{ // key changed but now a duplicate
throw new ArgumentException("Duplicate key");
}
else
{ // key changed; remove and re-add
_index.Remove(oldKey);
_index.Add(newKey, item);
}
base.SetItem(index, item);
}
}