Использование Linq для объектов, метод ToDictionary не удовлетворяет требованию типа - PullRequest
3 голосов
/ 10 марта 2012

Мне нужно передать переменную типа IDictionary<Guid, IEnumerable<Guid>> в метод.Когда я использую следующий код:

var userGroupDictionary = _selectedUsers.ToDictionary(u => u.UserGuid, u => u.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList());

, я получаю следующую ошибку:

cannot convert from System.Collections.Generic.Dictionary<System.Guid,System.Collections.Generic.List<System.Guid>>' to 'System.Collections.Generic.IDictionary<System.Guid,System.Collections.Generic.IEnumerable<System.Guid>>'

Когда я перебираю свою коллекцию, она работает, однако:

var userGroupDictionary = new Dictionary<Guid, IEnumerable<Guid>>();
foreach (var user in _selectedUsers.Where(user => !userGroupDictionary.ContainsKey(user.UserGuid)))
{
    userGroupDictionary.Add(user.UserGuid, user.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList());
}

Есть идеи, что происходит?Компилятор не может сказать, что Dictionary<Guid, List<Guid>> удовлетворяет IDictionary<Guid, IEnumerable<Guid>>

Ответы [ 4 ]

1 голос
/ 10 марта 2012

Проблема в том, что вывод типа возвращает Dictionary<Guid, List<Guid>>, который является неправильным типом для метода, который вы хотите вызвать.Это немного больше, чем это, но это включает обсуждение дисперсии типа.Вы можете решить проблему с помощью расширения AsEnumerable :

var userGroupDictionary = _selectedUsers
    .ToDictionary(
        u => u.UserGuid,
        u => u.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList().AsEnumerable());

... или выполнить простое приведение, как показано ниже:

var userGroupDictionary = _selectedUsers
    .ToDictionary(
        u => u.UserGuid,
        u => (IEnumerable<Guid>)u.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList());

Если вы просто опустите ToList(), как рекомендовали другие, вывод типа действительно отобразит ожидаемый вами тип, но возвращенный IEnumerable будет иметь отложенное выполнение, которое может быть или не быть проблемой для вас.Оставив там ToList, но выполнив приведение типов, вы сразу же оцените элементы, а не лениво оцениваете их во время итерации.

Для получения более подробной информации об отложенном выполнении см. «Лень»оценка) секция серии Edulinq Джона Скита, часть 44

1 голос
/ 10 марта 2012

Строка ниже создает словарь, в котором ключ типа Guid и значение типа List<Guid>.

_selectedUsers.ToDictionary(
                   u => u.UserGuid, 
                   u => u.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList()
                   );

Так что просто удалите .ToList() и все, u.GroupUsers.Select() само возвращает IEnumerable<Guid>.

И вы можете выполнять итерацию по обоим значениям, поскольку List также реализует IEnumerable, это достаточно для удовлетворения итератора foreach.

0 голосов
/ 10 марта 2012

Я думаю, что все пользователи u.GroupUsers имеют одинаковый идентификатор группы.Вы можете получить первый groupID, если вы можете получить доступ к свойству groupID в классе пользователя.Вы должны использовать GroupID.Как _selectedUsers.ToDictionary(u=>u.UserGuid,u.GroupID); Если вы не можете получить доступ к GroupId в классе пользователя.Использование:

_selectedUsers.ToDictionary(
                   u => u.UserGuid, 
                   u => u.GroupUsers.Select(gu => gu.Group.GroupGuid).First());
0 голосов
/ 10 марта 2012

Может ли компилятор сказать, что Dictionary<Guid, List<Guid>> удовлетворяет IDictionary<Guid, IEnumerable<Guid>>

Нет, компилятор может сказать, что Dictionary<Guid, List<Guid>> не удовлетворяет IDictionary<Guid, IEnumerable<Guid>>. Последний предоставляет, например, метод Add(Guid, IEnumerable<Guid>), который ваш словарь не может поддерживать.

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

_selectedUsers.ToDictionary<User, Guid, IEnumerable<Guid>>(
    u => u.UserGuid,
    u => u.GroupUsers.Select(gu => gu.Group.GroupGuid).ToList())
...