Один запрос LINQ на 3 отдельных коллекции - PullRequest
3 голосов
/ 18 марта 2012

У меня есть объект, который имеет 3 отдельных словаря.Параметр значения для каждого словаря реализует один и тот же интерфейс.Каков наилучший способ объединить 3 словаря в один и выполнить один запрос, чтобы результаты запроса были единым IEnumerable?

Вот примерное представление о том, чего я пытаюсь достичь.Мой DataSet объект содержит 3 словаря, каждый из которых должен быть очень маленьким (теоретически некоторые могут содержать до 100 элементов, но за исключением самых крайних случаев они всегда будут меньше 20 и обычно 6 или меньше).

Целью метода GetAllId() будет получение идентификатора для нескольких приватных полей в каждом элементе каждого словаря и возврат его в виде единого IEnumerable.Все объекты значений словаря реализуют IIdQueryable, который определяет один метод, который извлекает все необходимые Id в объекте.

У меня есть 2 разные идеи о том, как выполнить то, что я хочу, но я не уверен, есть ли лучший способ сделать это?

public class DataSet
{
    Dictionary<Int32, Foo> dict1;
    Dictionary<CustomKey, Bar> dict2;
    Dictionary<Int32, Boo> dict3;

    public IEnumerable<Int32> GetAllId
    {
        // need to retrieve Id from dict1, dict2, and dict3.
        //  implementation ideas below
    }
}

Вариант 1

public IEnumerable<Int32> GetAllId
{
    var q1 = dict.Values.SelectMany(g => g.GetId());
    var q2 = dict.Values.SelectMany(g => g.GetId());
    var q3 = dict.Values.SelectMany(g => g.GetId());

    return q1.Concat(q2).Concat(q3);
}

Опция 2

public IEnumerable<Int32> GetAllId
{
    var c1 = dict1.Values.Cast<IIdQueryable>();
    var c2 = dict2.Values.Cast<IIdQueryable>();
    var c3 = dict2.Values.Cast<IIdQueryable>();

    var collection = c1.Concat(c2).Concat(c3);

    return collection.SelectMany(g => g.GetId());
}

Метод # 3

Поскольку каждый объект реализует один и тот же интерфейс,Можно ли выполнить один запрос LINQ для всех трех объектов без приведения?

Лично мне больше нравится метод № 1, поскольку он ничего не включает в себя, но я думаю, что метод № 2 кажется более читабельным.

Если это необходимо, вот примерное представление о том, как реализован интерфейс

public interface IIdQueryable
{
    IEnumerable<Int32> GetId();
}

public class Foo : IIdQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

public class Bar : IGuidQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

public class Boo : IGuidQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

РЕДАКТИРОВАТЬ:

Название вопроса является источникомтого, что я надеялся сделать (то есть сделать все 3 поиска в одном запросе без приведения).Я уточнил это выше.

1 Ответ

2 голосов
/ 18 марта 2012

Вам нужен только один SelectMany звонок при первом подходе:

public IEnumerable<Int32> GetAllId()
{
    return dict1.Values
                .Select(x => x.GetId())
                .Concat(dict2.Values.Select( x=> x.GetId()))
                .Concat(dict3.Values.Select(x => x.GetId()))
                .SelectMany(x => x);
}

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

public IEnumerable<Int32> GetAllId()
{
    var q1 = dict1.Values.Select(g => g.GetId());
    var q2 = dict2.Values.Select(g => g.GetId());
    var q3 = dict3.Values.Select(g => g.GetId());

    return q1.Concat(q2)
             .Concat(q3)
             .SelectMany(x => x);
}

Теперь это выглядит довольно близко ко второму подходу - но не требуется приведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...