从List <t> </t>获取T属性列表的最佳方法

时间:2010-09-07 14:44:46

标签: c#

我有一个List<Users> - 用户有一个Username属性。

我想知道的是 - 有更好的方法来获取所有用户名的List<string>,而不是简单地循环并构建我的新列表吗?

5 个答案:

答案 0 :(得分:22)

使用LINQ:

List<string> usernames = users.Select(u => u.UserName).ToList();

答案 1 :(得分:12)

像这样:

List<string> userNames = users.ConvertAll(u => u.UserName);

请注意,userNames列表不会反映对users或其UserName的后续更改。

答案 2 :(得分:5)

如果你真的需要一个List,那么LINQ方法是你可以做的最好的(在创建一个具有适当容量然后添加的新List时可能会有一个边际速度提升,但它不太可能是明显的。

修改:如果您要执行此操作,请使用ConvertAll而不是Select,然后使用ToList,尤其是如果您的列表可能很大。 ConvertAll预分配到正确的大小,其重要性随着源列表的大小而增长。

如果你想要一个像你这样做的只读IList,那么你可以从转换列表类中获得更好的性能:

public class ConvertingList<TSrc, TDest> : IList<TDest>
{
  private readonly IList<TSrc> _inner;
  private readonly Func<TSrc, TDest> _conv;
  public ConvertingList(IList<TSrc> inner, Func<TSrc, TDest> conv)
  {
      _inner = inner;
      _conv = conv;
  }
  public TDest this[int index]
  {
      get
      {
          return ReferenceEquals(null, _inner[index]) ? default(TDest) : _conv(_inner[index]);
      }
      set
      {
        throw new NotSupportedException("Readonly collection");
      }
  }
  public int Count
  {
      get
      {
        return _inner.Count;
      }
  }
  public bool IsReadOnly
  {
      get
      {
        return true;
      }
  }
  public int IndexOf(TDest item)
  {
      if(ReferenceEquals(item, null))
      {
        for(int i = 0; i != Count; ++i)
          if(ReferenceEquals(this[i], null))
            return i;
      }
      else
      {
        for(int i = 0; i != Count; ++i)
          if(item.Equals(this[i]))
            return i;
      }
      return -1;
  }
  public void Insert(int index, TDest item)
  {
      throw new NotSupportedException("Readonly collection");
  }
  public void RemoveAt(int index)
  {
      throw new NotSupportedException("Readonly collection");
  }
  public void Add(TDest item)
  {
      throw new NotSupportedException("Readonly collection");
  }
  public void Clear()
  {
      throw new NotSupportedException("Readonly collection");
  }
  public bool Contains(TDest item)
  {
      return IndexOf(item) != -1;
  }
  public void CopyTo(TDest[] array, int arrayIndex)
  {
      if(array == null)
        throw new ArgumentNullException();
        if(arrayIndex < 0)
            throw new ArgumentOutOfRangeException();
        if(array.Rank != 1 || array.Length < arrayIndex + Count)
            throw new ArgumentException();
        foreach(TDest item in this)
          array[arrayIndex++] = item;
  }
  public bool Remove(TDest item)
  {
      throw new NotSupportedException("Readonly collection");
  }
  public IEnumerator<TDest> GetEnumerator()
  {
      foreach(TSrc srcItem in _inner)
        yield return ReferenceEquals(null,srcItem) ? default(TDest) : _conv(srcItem)
  }
  IEnumerator IEnumerable.GetEnumerator()
  {
      return GetEnumerator();
  }
}

有了这个,那么:

IList<string> userNames = new ConvertingList<User, string>(users, u => u.Username);

将在常量时间内创建一个新对象,其作为名称的只读列表。

(防止null用户在此处返回空字符串,当然可以提供其他行为)。

答案 3 :(得分:4)

var usernames = users.Select(u => u.Username).ToList();

答案 4 :(得分:1)

你做

List<string> userNames = users.ConvertAll(u => u.UserName);