【问题标题】:How do I refer to an item in a list<object> by Key rather than index?如何通过键而不是索引来引用 list<object> 中的项目?
【发布时间】:2012-05-23 19:21:03
【问题描述】:

我有一个包含List&lt;&gt; 对象的类。对于这个例子,我会说对象是一个基本类,如下所示:

public class City
{
    private string name;
    private string country;

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

通常我会这样引用这些对象:

List<City> theList = new List<City>();
City theCity = theList[0];

我想做的是参考以下列表:

List<City> theList = new List<City>();
City theCity = theList["London"];

其中伦敦是其中一个城市的名称属性。

我如何实现这一目标?目前我一直在构建“查找”类型的方法来返回我所讨论的城市。我需要的是能够通过Key引用。

【问题讨论】:

  • 您不能确定列表中只有一个具有指定“键”的项目。最好使用字典。

标签: c# list key


【解决方案1】:

基本上,听起来您想要Dictionary&lt;string, City&gt; 而不是List&lt;City&gt;。您可以使用 LINQ 轻松创建它:

var dictionary = list.ToDictionary(city => city.Name);

如果您真的想保留顺序,可以使用列表并搜索它(根据 Ethan 的回答),但如果您需要按名称查找,那么字典就是你想要的。

【讨论】:

  • 感谢您的建议,不确定是否将它们全部转换为字典(有多个列表),并且在我实际处理的示例中顺序很重要....感谢您这么快回复.
【解决方案2】:

您编写一个包装器 List 类 CityList 并重载 [] 运算符。

public class City
{
    private string name;
    private string country;

    public City(string cityName)
    {
        Name = cityName;
    }

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

public class CityList : CollectionBase
{
    public CityList() : base ()
    {
    }

    public City this[int index]
    {
        get
        {
            return (City)List[index];
        }
        set
        {
            List[index] = value;
        }
    }

    public City this[string name]
    {
        get
        {
            int index = this.IndexOf(name);
            if (index < 0 || index >= this.List.Count) return null; // or assert

            return (City)List[index];
        }
        set
        {
            int index = this.IndexOf(name);
            if (index > 0 || index >= this.List.Count) return; // or assert
            List[index] = value;
        }
    }

    public virtual int IndexOf(City city)
    {
        return List.IndexOf(city);
    }

    public virtual int IndexOf(string name)
    {
        if (name == null) return -1;

        for (int i = 0; i < List.Count; i++)
        {
            if (((City)List[i]).Name.ToLower() == name.ToLower())
                return i;
        }
        return -1;
    }

    public virtual void Insert(int index, City city)
    {
        List.Insert(index, city);
    }

    public virtual int Add(City city)
    {
        return base.List.Add(city);
    }
}

class Program
{
    static void Main()
    {
        City NewYork = new City("New York");
        City Boston = new City("Boston");
        City Tampa = new City("Tampa");

        CityList cities = new CityList();
        cities.Add(NewYork);
        cities.Add(Boston);
        cities.Add(Tampa);

        Console.WriteLine(cities["Boston"].Name); // prints "Boston"

        Console.ReadKey();
    }
}

现在可能有一种更巧妙的方法可以做到这一点,因此您不需要演员表。这就像 .NET 2.0 代码。

【讨论】:

  • 你能给我一个如何做到这一点的例子(使用基本的城市类例子),谢谢
  • 我为你添加了一些示例代码。为了简洁起见,我省略了一些您可能会实现的方法(例如 addrange、remove 等)
  • 最好从Collection&lt;City&gt;派生,使用System.Collections.ObjectModel。然后你就不必投了。也可以从List&lt;City&gt; 派生,这将是最容易编写的解决方案,但不一定是最好的解决方案。另一种方法是不从任何集合类派生,然后将可访问的List&lt;City&gt; 作为您的类CityList 的成员。
【解决方案3】:

您可以使用 LINQ:

List<City> theList = new List<City>();
City theCity = theList.FirstOrDefault( x => x.Name == "London" );

【讨论】:

  • 他说他已经在使用List Find方法了,这里没有理由使用LINQ。它更长,理论上更慢,虽然我没有测试过。
  • 这些是小列表(实际列表项只有 20-30 长)。我没有提到我需要保留订单(但我这样做了!).. 所以谢谢你的建议
【解决方案4】:

System.Collections.ObjectModel.KeyedCollection怎么样?

http://msdn.microsoft.com/en-us/library/ms132438.aspx

【讨论】:

    猜你喜欢
    • 2019-04-21
    • 2010-12-14
    • 2015-12-13
    • 1970-01-01
    • 2011-01-25
    • 2016-08-04
    • 2014-11-14
    • 2017-08-27
    • 1970-01-01
    相关资源
    最近更新 更多