Можно ли преобразовать результат метода расширения LINQ "Take" в исходный тип? - PullRequest
3 голосов
/ 18 апреля 2019

Если я применяю метод расширения LINQ Take к SortedList<int, int>, как мне преобразовать результат в новый SortedList<int, int>?

Из-за полученной ошибки времени выполнения метод Take является EnumerablePartition, который не может быть приведен к SortedList<int, int>

Основной метод в консольном приложении компилируется нормально, но выдает ошибку во время выполнения при приведении результата list.Take (2) к SortedList

        static void Main(string[] args)
        {
            Console.WriteLine("List");

            var list = new SortedList<int, int>();

            list.Add(2, 10);
            list.Add(8, 9);
            list.Add(3, 15);

            foreach (KeyValuePair<int, int> item in list){
                Console.WriteLine(item.Value);
            };

            Console.WriteLine("Short List");

            var shortlist = (SortedList<int, int>)list.Take(2);

            foreach (KeyValuePair<int, int> item in shortlist)
            {
                Console.WriteLine(item.Value);
            };

            Console.Read();

        }

Я бы ожидал, что результатом Take будет новый SortedList<int, int> или, по крайней мере, его можно будет привести к SortedList<int, int>, учитывая, что это исходный тип.

Вот ошибка выполнения, которую я получаю:

Unable to cast object of type 'EnumerablePartition`1[System.Collections.Generic.KeyValuePair`2[System.Int32,System.Int32]]' to type 'System.Collections.Generic.SortedList`2[System.Int32,System.Int32]'

EDIT:

Я относительно новичок в LINQ и Generics, но благодаря полученным отличным ответам я создал новый метод расширения для удобства чтения:

    static class Extensions {

        public static SortedList<TKey, TValue> ToSortedList<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> collection)
        {
            var dictionary = collection.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            return new SortedList<TKey, TValue>(dictionary);
        }
    }

Теперь, чтобы создать мой список:

var shortlist = list.Take(2).ToSortedList();

Я думал, что что-то подобное может быть уже доступно!

Ответы [ 4 ]

8 голосов
/ 18 апреля 2019

Я бы ожидал, что результатом метода Take будет новый SortedList или, по крайней мере, будет возможно приведение к SortedList, учитывая, что это оригинальный тип.

Ну, это не совсем так.Если вы Take(2) из пакета сладостей, у вас есть две сладости.У вас нет волшебной сумки с двумя конфетами просто потому, что в сумке были оригинальные конфеты.

Технически говоря, метод Take принимает IEnumerable<> любого типа и возвращает IEnumerable<> того же типа.Информация о типе оригинального контейнера теряется в процессе.

Теперь, очевидно, как в нашем примере со сладостями, если вы хотите, чтобы имели крошечные пакеты по две конфеты в каждой из вашей большой сумки,никто не мешает вам переупаковывать их.Тоже самое.Если вам нужен отсортированный список, создайте новый отсортированный список из результата.Но это руководство.

2 голосов
/ 18 апреля 2019

Вы можете использовать SortedList конструктор

var sortedList = new SortedList<int, int>(list.Take(2).ToDictionary(x => x.Key, x => x.Value));
1 голос
/ 18 апреля 2019

, учитывая, что это оригинальный тип

Да, но Take() - это метод расширения для IEnumerable<T>, а SortedList<TKey, TValue> реализует IEnumerable<KeyValuePair<TKey, TValue>>.

Таким образом, тип, который вы возвращаете из Take(), не должен иметь никакого отношения к источнику, к которому вы его вызываете - он просто возвращает реализацию IEnumerable<T>, где T такого же типа, как T изIEnumerable<T>, который вы вызываете.

Вместо этого создайте новый список, используя раздел и его соответствующий конструктор :

var shortlist = new SortedList<int, int>(list.Take(2).ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
1 голос
/ 18 апреля 2019

Take не возвращает SortedList, поэтому вам нужно так или иначе создать новое:

var shortList = new SortedList<int, int>();
foreach (var x in list.Take(2))
   shortList.Add(x.Key, x.Value);
...