Запрос словаря C # с использованием лямбда-выражений

#c# #linq #dictionary #lambda

#c# #linq #словарь #лямбда

Вопрос:

Допустим, у меня есть этот объявленный словарь:

  private static Dictionary<int, List<Models.APIAccessControl>> _APIRights = GetAPIRights();
  

Где ключ представляет идентификатор роли, значение представляет класс:

  public class APIAccessControl
{
    public APIControllerRoute ControllerRoute { get; set; }
    public APIActionRoute ActionRoute { get; set; }
    public bool IsAuthorized { get; set; }

}
  

Я пытаюсь проверить, авторизован ли пользователь для доступа к этому api.
Моя идея состоит в том, чтобы запросить словарь и получить весь список APIAccessControl для ролей, а затем запросить эти списки APIAccessControl для APIActionRoute, по которому он пытается перемещаться:

Я получил значения словаря, которые содержат список для нужных мне ролей, но как преобразовать список значений в список и выполнить этот запрос:

 public static bool CanAccess(int[] roleIDs, APIActionRoute apiActionRoute)
   {
            bool canAccess = false;

            var apiAccessList = _APIRights.Where(x => roleIDs.Contains(x.Key)).Select(x => new { x.Value}).ToList();

      //Querying to get all List<Models.APIAccessControl> that has any matchig   APIActionRoute
    }
  

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

1. Вы можете попытаться извлечь список, используя свойство Values словаря.

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

3. Вам придется использовать цикл над apiAccessList, чтобы получить все ActionRoutes и добавить их в список. Есть альтернатива. Единственное, что вы можете сделать, это использовать Linq. Дайте мне знать, если это что-нибудь прояснит

Ответ №1:

Вы можете изменить предложение Select, чтобы получить нужный вам список:

 var apiAccessList = _APIRights.Where(x => roleIDs.Contains(x.Key))
    .SelectMany(x => x.Value).ToList();
  

Не выбирая анонимный класс и используя SelectMany , список будет иметь тип Models.APIAccessControl

Ответ №2:

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

 bool canAccess = false;
foreach(var roleId in roleIDs)
{
    List<Models.APIAccessControl> controls;
    if(_APIRights.TryGetValue(roleId, out controls))
    {
        canAccess = controls.Any(control => control.ActionRoute.Equals(apiActionRoute));
        if(canAccess)
            break;
    }
}
  

Вам нужно убедиться Equals , что на самом деле выполняется тот тип сравнения, который вы хотите. По умолчанию это будет ссылочное равенство, и вам придется перегрузить его внутри APIActionRoute , если вы хотите равенства значений, или вместо этого использовать сравнение желаемых свойств.

Полностью версия Linq немного запутана

 List<Models.APIAccessControl> controls;
bool canAccess = roleIDs.Any(
    r => _APIRights.TryGetValue(r, out controls) 
          amp;amp; controls.Any(
              control => control.ActionRoute.Equals(apiActionRoute)));
  

Ответ №3:

Звучит так, как вы хотите SelectMany , который проецирует «список списков» в один список:

 var apiAccessList =
   _APIRights
   .Where(x => roleIDs.Contains(x.Key))
   .SelectMany(x => x.Value)
   .ToList();
  

Тогда у вас будет каждый APIAccessControl объект в одном большом списке. Однако он больше не будет группироваться по идентификатору роли. В нем также могут быть дубликаты, которые могут иметь или не иметь значения.

Ответ №4:

Я думаю, что SelectMany может помочь.

 public static bool CanAccess(int[] roleIDs, APIActionRoute apiActionRoute)
{
    return _APIRights.Where(x => roleIDs.Contains(x.Key))
        .SelectMany(x => x.Value)
        .Any(a => a.ActionRoute == apiActionRoute);
}