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

And*_*ndy 8 c#

我有一个List<Users>- 用户有一个用户名属性.

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

Arc*_*rus 22

使用LINQ:

List<string> usernames = users.Select(u => u.UserName).ToList();
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 12

像这样:

List<string> userNames = users.ConvertAll(u => u.UserName);
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*nna 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,那么:

IList<string> userNames = new ConvertingList<User, string>(users, u => u.Username);
Run Code Online (Sandbox Code Playgroud)

将在恒定时间内创建一个新对象,该对象表现为名称的只读列表.

(针对null用户的安全措施在此处返回空字符串,当然可以提供其他行为).