简体   繁体   中英

Retrieval of items from custom collection

I have a following class

public class People
{
    public int id;
    public string nameHash;
    public string name;
}

I need to create a custom collection, consisting of objects of class People , that lets me retrieve elements by its id and nameHash . The collection must have the ability to iterate through its elements using foreach:

foreach (People person in PeopleCollection) { ... }

How do I do that? If you can not give a detailed answer, at least give a brief plan of action. Thanks in advance!

Is there a specific reason why it has to be a custom collection? Why not

List<People> PeopleCollection = new List<People>();

you can retrieve elements using id and nameHash and you can iterate over PeopleCollection

class PeopleList : List<People> {

}

That's pretty much it. Just inherit from List<T> and you're set.

BTW, you should reconsider your naming conventions. 'People' is not a good name for a class that represents a single person. Name it 'Person' instead, and name your list 'People'.

If you're talking about a large collection and you want faster lookups based on an integer Id or a string NameHash field while still supporting the foreach (Foo f in fooCollection) pattern, then you can roll your own collection that wraps a pair of dictionaries. Crude implementation, not thoroughly tested:

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

    public Person(int id, string nameHash, string name)
    {
        Id = id;
        NameHash = nameHash;
        Name = name;
    }
}

class People : IEnumerable<Person>
{
    private Dictionary<int, Person> personDictionary = new Dictionary<int, Person>();
    private Dictionary<string, int> hashIdMap = new Dictionary<string, int>();

    public void Add(Person person)
    {
        if (person == null)
            throw new ArgumentNullException("person");

        if (personDictionary.ContainsKey(person.Id))
            throw new InvalidOperationException("person Id is already referenced in collection.");

        if (hashIdMap.ContainsKey(person.NameHash))
            throw new InvalidOperationException("person NameHash is already referenced in collection.");

        personDictionary.Add(person.Id, person);
        hashIdMap.Add(person.NameHash, person.Id);
    }

    public Person this[int id]
    {
        get
        {
            if (!personDictionary.ContainsKey(id))
                throw new ArgumentOutOfRangeException("Id is not in the collection.");

            return personDictionary[id];
        }
    }

    public Person this[string nameHash]
    {
        get
        {
            if (!hashIdMap.ContainsKey(nameHash))
                throw new ArgumentOutOfRangeException("NameHash is not in the collection.");

            return this[hashIdMap[nameHash]];
        }
    }

    public IEnumerator<Person> GetEnumerator()
    {
        foreach (KeyValuePair<int, Person> pair in personDictionary)
            yield return pair.Value;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

...

static void Main()
{
    Person personA = new Person(1, "A", "Apple");
    Person personB = new Person(2, "B", "Banana");
    Person personC = new Person(3, "C", "Cherry");

    People people = new People();
    people.Add(personA);
    people.Add(personB);
    people.Add(personC);

    Person foo = people[1];
    Person bar = people["C"];

    Debug.Assert(foo.Name == "Apple");
    Debug.Assert(bar.Name == "Cherry");

    foreach (Person person in people)
        Debug.WriteLine(person.Name);
}

Of course, if you're dealing with a small-ish collection, you could very well simply use a List<T> and utilize either LINQ or the Find methods already defined. Such as

Person personA = collection.FirstOrDefault(p => p.Id == 42);
Person personB = collection.Find(p => p.NameHash == "Blah");

You have two choices here:

  1. Inherit from an existing collection type, as shown in other answers.
  2. Implement the System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> interface, which also means writing your own implementation of System.Collections.IEnumerator or System.Collections.Generic.IEnumerator<T>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM