#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);
}