Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.96/92: Рейтинг темы: голосов - 92, средняя оценка - 4.96
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272

Преобразование list<type1> в list<type2>

23.07.2012, 11:14. Показов 17956. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, недавно начал изучать с#. Накопилось много вопросов)
но сейчас интересует один конкретный.
объём кода - пара сотен строк и дюжина классов...так что думаю, будет проблематично всю сюда свалить
(сам вопрос внизу. Описание самой программы можно даже не читать. Читать его нужно только, если то, о чём я спрашиваю - реализовать нельзя.)
Смысл такой: будет серия похожих программ, которые сравниваю 2 версии "чего-то там" (хранятся на SQL). Чтобы не писать каждый раз с нуля, я решил сделать 2 части проекта:
1 - базовая часть. Туда входят:
-классы, необходимые для распознавания изменений в разных версиях "чего-то там"(нас интересует только великий "БАЗОВЫЙ ТИП", по которому, собственно, и вопрос.)
-базовые классы, представляющие общие свойства, методы этого "чего-то там"
-интерфейсы и абстрактные классы (один из которых содержит интерфейс доступа к данным SQL базы - назовём его "ConnectorBase")

2 - сменная часть. Туда входят:
-производные от базовых классов и интерфейсов из пункта 1. Для нас важны: наследник "БАЗОВОГО ТИПА" - назовём его "ПРОИЗВОДНЫЙ ТИП"
и
наследник абстрактного класса, отвечающий за доступ к sql серверу (назовём его "Connector"), т.к. именно он и формирует и сам запрос, а также преобразует результат запроса в List<"ПРОИЗВОДНЫЙ ТИП">


Две части связываются вместе с помощью моего собственного простенького "IoC-Контейнера".
Как это работает:
класс "Connector" создаёт "List<Производный тип>", преобразует его в "List<Базовый тип>" и передаёт классу из части 1
класс из части 1 хранит полученный "List<Базовый тип>" и, с помощью своих методов формирует разные новые List<Базовый тип>, в которые входят некоторые элементы из старого списка.
В принципе всё - вот этот новый List<Базового типа> - это ответ, но в последующей части программы, мне нужно преобразовать "ответ" List<Базовый тип> в List<Производный тип>. В этом вся проблемма
Решил я пока её плохо - создавать ещё один НОВЫЙ List<Производный тип> и, с помощью foreach и преобразования копировать элементы из List<Базовый> в List<Производный>. Хочется сделать что-то такое
C#
1
2
List<VersionInfoBasic.VersionInfoBasic> list = a.GetDeleted();
var c = list as List<VersionInfoStrukturaKompleksa>;
Есть ещё 1 вариант - везде использовать "производный тип". Но тогда часть 1 станет зависимой от части 2. И мне придётся писать больше кода - так себе затея.

Сам вопрос - можно ли как-то преобразовать List<ПроизводныйТип> в List<БазовыйТип> (ну и наоборот), не прибегая к foreach для каждого элемента списка. (мне уже советовали LINQ выражения, о которых я пока ничего не знаю, но сказали, что принцип его работы такой же, как и у foreach). и далее, если нельзя...то насколько "правильной" можно считать программу (описанную выше) которая для своей работы создаёт ПроизводныйТип, потом преобразует его в БазовыйТип, работает с ним, а, для получения конечного ответа, преобразует его опять же в ПроизводныйТип
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.07.2012, 11:14
Ответы с готовыми решениями:

Linq преобразование List<List<double>> в List<Array>
Доброго времени суток, данный код нужно преобразовать linq выражениями и дописать выборку из List&lt;List&lt;double&gt;&gt;. Таким...

Преобразование List<Child> to List<Parent> и обратно
Здравствуйте, подскажите пожалуйста, как правильно реализовать преобразование списка объектов класса наследника в список объектов родителя...

Конвертировать один элемент из List<List<Class>> в list и string
Как можно перевести один выбранный элемент из List&lt;List&lt;Data&gt;&gt; myList в list и string? Например, myList. Сейчас я могу с помощью...

13
 Аватар для SandWraith
189 / 189 / 38
Регистрация: 11.04.2009
Сообщений: 497
23.07.2012, 12:05
тред не читал@сразу отвечал: см. следующее:
Ковариантность и контравариантность
Cast<T>
OfType<T>
0
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
23.07.2012, 14:17  [ТС]
Cast<T>
OfType<T> - это пока не смотрел, а вот про Ковариантность и контравариантность почитал.

и тут же возник вопрос))
C#
1
2
IEnumerable<VersionInfoBasic.VersionInfoBasic> b = a.GetDeleted();
            IEnumerable<VersionInfoStrukturaKompleksa> c = b;
VersionInfoStrukturaKompleksa - наследник VersionInfoBasic
оно же должно работать?
p.s.
C#
1
public IEnumerable<VersionInfoBasic> GetDeleted()
делал аналогично примеру:
Если у вас есть иерархия классов, скажем, с типом Employee и типом Manager, производным от Employee (менеджеры — ведь тоже наемные работники), то, как по-вашему, что делает следующий код?

C#
1
2
IEnumerable<Manager> ms = GetManagers();
IEnumerable<Employee> es = ms;
________________________________________ _______________
а, понял...тут я пытаюсь использовать контравариантность, полагаясь на пример ковариантности...
интерфейс IEnumerable не поддерживает контравариантность, так?

Добавлено через 12 минут
Итого, пока для себя думаю так:
IEnumerable подерживает конвариантность (из производного в базовый) как неявное преобразование.
А, чтобы произвести обратное преобразование нужно написать
C#
1
IEnumerable<VersionInfoStrukturaKompleksa> c = b.Cast<VersionInfoStrukturaKompleksa>();
Добавлено через 10 минут
Если я всё понял правильно,то осталось только понять одну мелочь - после "каста"
C#
1
var c = b.cast<...>
поле 'value' переменной "с" в столбце "Watch" принимает значение {System.Linq.Enumerable.CastIterator<Str ukturaKompleksa.VersionInfoStrukturaKomp leksa>}
тогда как поле "value" переменной "b" Count = 17
означает ли это то, что элементы коллекции c становятся "итераторами", которые при обращении к элементу делают преобразование типа во время выполнения программы?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
24.07.2012, 07:04
Ковариантность означает, что можно сделать неявное приведение, даже без Cast.
C#
1
2
3
4
5
6
    public class B{}
    public class A : B{}
    //...
    A[] arr = new A[] {new A(), new A(), new A()};
    IEnumerable<A> enumerable = arr.Where(a => a != null);
    IEnumerable<B> enumB = enumerable;
Для того чтобы это работало, generic тип должен быть объявлен с ключевым словом out:
C#
1
public interface IEnumerable<out T> : IEnumerable
Добавлено через 2 минуты
Цитата Сообщение от IcyWind Посмотреть сообщение
означает ли это то, что элементы коллекции c становятся "итераторами", которые при обращении к элементу делают преобразование типа во время выполнения программы?
Нет, не означает. Итератор - это нечто, что может возращать значения, когда вы их об этом попросите. По началу можете считать, что итератор это нечто вроде коллекции.
Вам должно быть важно только то, что тип который возвращает Cast может быть приведен к IEnumerable<T>.
0
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
24.07.2012, 10:39  [ТС]
Ясно. Почитал ещё на msdn про cast и получилось, что я вроде как вернулся к тому, с чего начинал)
т.к. возвращаемое значение каста "Объект IEnumerable<T>, который содержит все элементы исходной последовательности, преобразованные в заданный тип.", что эквивалентно преобразованию каждого элемента через foreach, так?
и всё-равно никак не получается заставить работать неявное преобразование. Что не так?
1.)
C#
1
public abstract class VersionInfoBasic
- это базовый
C#
1
public class VersionInfoStrukturaKompleksa : VersionInfoBasic.VersionInfoBasic
- это производный
2.) IEnumerable<T> - это встроенный тип, который объявлён с помощью модификатора out. Поэтому с ним мне ничего делать не надо. И в методах, в качестве типа возвращаемого значения я пишу просто IEnumerable<БАЗОВЫЙ КЛАСС>, за которым у меня скрывается List<Производный класс>. Тут никаких проблем не происходит. Список из производных неявно преобразуется в IEnumerable<Базового>. Это пример ковариантности.
3.) Дальше я поработал с IEnumerable<Базовый> и хочу получить из него IEnumerable<Производный>, для этого пишу
C#
1
IEnumerable<StrukturaKompleksa.VersionInfoStrukturaKompleksa> b = a.GetChanged();
где GetChanged()
C#
1
public IEnumerable<VersionInfoBasic> GetChanged()
и получаю
Error 1 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable< VersionInfoBasic.VersionInfoBasic>' to 'System.Collections.Generic.IEnumerable< StrukturaKompleksa.VersionInfoStrukturaK ompleksa>'. An explicit conversion exists (are you missing a cast?) G:\БрЭд\ComparerSolution\ConsoleApplicat ion1\Program.cs 15 79 ConsoleApplication1
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
24.07.2012, 11:04
IEnumerable ковариантен (можно делать приведение к базовому типу), но не контрвариантен(можно делать приведение к дочернему тупу).
Поэтому нужен Cast, если вы действительно уверены, что все элементы будут точно дочернего типа.
C#
1
IEnumerable<StrukturaKompleksa.VersionInfoStrukturaKompleksa> b = a.GetChanged().Cast<StrukturaKompleksa.VersionInfoStrukturaKompleksa>();
PS. А почему бы не сделать GetChanged обобщенным? Тогда и Cast не нужен будет.
0
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
24.07.2012, 11:16  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
А почему бы не сделать GetChanged обобщенным? Тогда и Cast не нужен будет
эээ, пойду изучать...про них пока не слышал. Старая книжка Шилда о них не знает))
как почитаю - вернусь

Добавлено через 3 минуты
А, "обобщённый" в c# - это "шаблонный" в c++. Щас только разберусь, насколько он будет доверять тому, что в каком-то типе Т будет куча разных методов
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
24.07.2012, 11:31
Цитата Сообщение от IcyWind Посмотреть сообщение
А, "обобщённый" в c# - это "шаблонный" в c++. Щас только разберусь, насколько он будет доверять тому, что в каком-то типе Т будет куча разных методов
http://msdn.microsoft.com/ru-ru/library/c6cyy67b
0
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
24.07.2012, 11:51  [ТС]
эх...не хочет компилятор верить, что в каком-то неизвестном, шаблонном типе Т есть какие-то свойства...методы...
например
C#
1
2
3
4
5
6
7
public class shab<T>
    {
        public shab(T ob)
        {
            ob.Print();
        }
    }
Печально...чем дальше изучаю язык, тем сильнее понимаю, что компилятор программисту даёт очень мало места для творчества
хотя и защищает от большого кол-ва ошибок

Хотел заменить весь Базовый тип на Т, но не получается...т.к. запись, вроде Т.Group или T.Symonyme(t) - невозможны(
единственное полезное применение от "обобщения" класса, где определён метод "GetChanged()" я могу получить в том, что уже в самом методе можно будет сделать cast и возвратить список нужного мне типа

Осталось только про каст уточнить...
Цитата Сообщение от IcyWind Посмотреть сообщение
возвращаемое значение каста "Объект IEnumerable<T>, который содержит все элементы исходной последовательности, преобразованные в заданный тип.", что эквивалентно преобразованию каждого элемента через foreach, так?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
24.07.2012, 12:01
Цитата Сообщение от IcyWind Посмотреть сообщение
чем дальше изучаю язык, тем сильнее понимаю, что компилятор программисту даёт очень мало места для творчества
Изучайте дальше. На тип T можно накладывать ограничения. Одно из возможных ограничений - обязать, чтобы тип T был наследником другого типа, например, вашего базового VersionInfoBasic.
И тогда он разрешит вызывать все методы, которые есть в VersionInfoBasic.
C#
1
2
3
4
5
6
7
    public class shab<T> where T : VersionInfoBasic
    {
        public shab(T ob)
        {
            ob.Print();
        }
    }
топик про c# generic на rsdn
1
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
24.07.2012, 12:57  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
Спасибо, уже большую часть дочитал - чуть-чуть осталось
хороший механизм)
хотел только поспорить с логикой тех, кто назвал это "ограничением", а базовый object - свободным. (относительно where T : БазовыйКласс и where T : Интерфейс, с остальным тремя(where T : new(), where T : class, where T : struct) согласен - это именно ограничения).

Как по мне, object - должен быть самым ограниченным из всех, в том смысле, что у него очень мало возможностей. А любой where - расширяет возможности шаблонного типа, добавляет свойства, поля, методы, и т.д.

Кстати в плюсах хотели ввести подобные ограничения (концепты). Но там эта формулировка ("ограничение") больше подходит под смысл самого механизма. Обычный шаблонный тип Т - может всё (свободный), но, стоит добавить концепт и тогда мы ограничим кол-во классов, которые можно подставлять вместо Т.
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
24.07.2012, 13:51
Обобщенные типы все же пишут реже, чем используют.
А для тех, кто использует generic, это все таки ограничение - не дает создать generic с произвольным типов.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
24.07.2012, 17:47
IcyWind, как раз-таки максимально свободным является object, свобода имеется ввиду возможность приведения, то есть если у нас есть массив object, то у нас есть свобода в выборе передаваемого значения (любой класс, любая структура), а если у нас массив какого-то хитрого класса, то только этот класс и его наследники могут передаваться, то есть получается менее обобщенный класс, следовательно менее свободный. Логика как раз-таки правильная. Object является наиболее свободным, т.к. к нему можно привести любой другой класс/структуру.
0
9 / 9 / 9
Регистрация: 19.09.2011
Сообщений: 272
25.07.2012, 10:34  [ТС]
Убедили
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
25.07.2012, 10:34
Помогаю со студенческими работами здесь

Как узнать размерность внутреннего вектора в массиве List<List<Double>>?
Добрый вечер! Уважаемые, подскажите пожалуйста, как узнать размерность внутренних строк в двумерном массиве типа List? Создаю...

List<string> или все же List<StringBuilder>, что лучше использовать?
Добрый день, хочется узнать с точки зрения производительности что подходит лучше в данном случае. Есть List&lt;List&lt;T&gt;&gt;, в...

Необходимо создать dll в которой буду обрабатывать list<list<string>>
Необходимо создать dll в которой буду обрабатывать list&lt;list&lt;string&gt;&gt; как объявить методы класса чтобы я задавал на вход экземпляр...

Найти минимальный элемент List<List<int?>>, не используя циклов
Имеется List&lt;List&lt;int?&gt;&gt; matrix = new List&lt;List&lt;int?&gt;&gt;(); список. Есть ли возможность найти минимальный элемент из всей этой матрицы без...

List<List<float>> Или как оперировать коллекцией в колекции
Есть ряд точек с координатами x,y, через гипотенузу буду рассчитывать дистанцию друг от друга class CoorXY { public float...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru