Как убедиться, что пользователь добавляется в список только один раз

#c# #linq #sharepoint-2007

#c# #linq #sharepoint-2007

Вопрос:

Мне нужно составить список пользователей с помощью пользовательского поиска, где я беру всех пользователей из всех групп, добавленных в список разрешений в sharepoint web. Моя проблема в том, что пользователи могут состоять в нескольких группах, поэтому они добавляются несколько раз в возвращаемый список. Как мне убедиться, что он добавляется только один раз?

C#

 // keywords is the whatever value a user types into the search textbox
private static IEnumerable<SPUser> GetUsers(SPWeb web, string keywords)
    {
        var oList = new List<SPUser>();
        var oListUsers = web.Groups.Cast<SPGroup>().SelectMany(grp => grp.Users.Cast<SPUser>().Where(user => user.Name.Contains(keywords))).ToList();

        foreach (SPUser user in oListUsers)
        {
            // My attempt here is to check if the list already contains the current item
            // but it seems to ignore it. I've tried counting too, but same outcome.
            if (!oList.Contains(user))
                oList.Add(user);
        }

        return oList;
    }
  

Комментарии:

1. oList. Contains(user) возвращает false, даже если пользователь есть в этом списке?

2. .Contains() проверяет ссылку, является ли тип ссылочным типом, и возвращает false, если oList не содержит ссылки на тот же объект, на который ссылается текущая итерация user. Однако вы можете переопределить . Метод Equals() в классе для принудительного выполнения определенного сравнения (для пользователя. Свойство Name, например).

Ответ №1:

Попробуйте это (вместо contains)

  if (! oList.Any(u => u.Name == user.Name ))
 {
      oList.Add(user);
 }
  

Ответ №2:

Похоже, вашему классу SPUser необходимо реализовать IEquatable<SPUser> , чтобы containes работал так, как вы этого хотите.

Ответ №3:

Вы можете использовать Linq для получения уникальных записей

 var uniqueValues = oList.Distinct();
  

Это приведет к удалению SPUser объекта с той же ссылкой. Также вы можете реализовать IEqualityCompaprer<SPUser> для своей собственной логики равенства

Ответ №4:

Используйте Hashset вместо списка. Таким образом, вам не нужно проверять наличие содержимого, а повторяющиеся элементы будут просто игнорироваться.

Это тоже будет быстрее, поскольку HashSet способен отклонять дубликаты почти тривиально, в то время как List<>.Contains() равен O (n)

  var oList = new HashSet<SPUser>();
    var oListUsers = web.Groups.Cast<SPGroup>().SelectMany(grp => grp.Users.Cast<SPUser> ().Where(user => user.Name.Contains(keywords))).ToList();

    foreach (SPUser user in oListUsers)
    {
      oList.Add(user);
    }
  

Ответ №5:

Используя грубую силу, вы могли бы просто использовать Distinct:

 var oListUsers = web.Groups.Cast<SPGroup>().SelectMany(grp => grp.Users.Cast<SPUser>().Where(user => user.Name.Contains(keywords))).Distinct().ToList();
  

Ответ №6:

Проблема в том, что в вашем oListUsers списке есть разные объекты, которые представляют одного и того же пользователя, но имеют разные ссылки на объекты — поскольку Contains() для проверки используются ссылки на объекты, вы не сможете отследить этот случай, если не определите пользовательский компаратор / равенство в вашем SPUser классе.

В качестве альтернативы, если, например, имя пользователя уникально, вы могли бы отфильтровать дубликаты таким образом.