Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/15: Рейтинг темы: голосов - 15, средняя оценка - 5.00
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923

Преобразование типов разных слоёв

23.08.2021, 21:36. Показов 3187. Ответов 37
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Допустим у меня где-то там, в приложении, есть какие-то API. Так как результатом будет json-response я создал отдельный тип под него:

C#
1
2
3
4
5
6
7
    public class Student
    {
        [JsonProperty("id")]
        public string Id { get; set; }
        [JsonProperty("name")]
        public string Name { get; set; }
    }
Далее у меня работа с слоями MVVM паттерна, но роли это не играет, ведь альтернативой может быть и MVC и MVP и т.д. Для него я, обычно, использую иммутабельный Dto-тип.

C#
1
2
3
4
5
6
7
8
9
10
    readonly public struct StudentReadOnlyStruct
    {
        public string Id { get; }
        public string Name { get; }
 
        public StudentReadOnlyStruct(string id, string name)
        {
            Id = id; Name = name;
        }
    }
Допустим мне пришла с сервера коллекция -- 10 студентов IDictionary<string, Student>.
Также у меня уже где-то в моделе лежит список 10 студентов IDictionary<string, StudentReadOnlyStruct> из прошлого запроса. Допустим 9 студентов, которые результируют запрос, остались прежними, а один студент изменился.

Задача: проверить, какой из 10 новых студентов изменился и заменить его в списке IDictionary<string, StudentReadOnlyStruct>.

Я вижу тут 2 решения:
- банально перевести первую коллекцию в тип второй коллекции, а потом их сравнить(но мне кажется это слишком дорого).
- попробовать помудрить что-то с хешами.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.08.2021, 21:36
Ответы с готовыми решениями:

Создать массивы разных типов(3 типов), вывести их на экран
Создать массивы разных типов(3 типов), вывести их на экран.

Преобразование типов
Есть такая заковырка. Допустим есть переменая string a=&quot;54&quot;; , так вот как ее можно преобразовать к типу int или другому числовому типу,...

Преобразование типов
Всем привет есть вопросы по преобразованию типов точнее даже не знаю относиться ли эта проблема к этому. вот код public class...

37
Злой няш
 Аватар для I2um1
2136 / 1505 / 565
Регистрация: 05.04.2010
Сообщений: 2,881
24.08.2021, 09:44
Цитата Сообщение от limeniye Посмотреть сообщение
Так как результатом будет json-response я создал отдельный тип под него
Обычно добавляются различные префиксы/суффиксы, например:

Красный - модели работы с API. Специфические вещи для передачи и представления данных как, например, дата в формате ISO 8601.
Зеленый - обслуживающие классы, которые делают полезную работу. Понятия, которыми оперирует владелец предметной области.
Фиолетовый - классы, отражающие способ хранения данных. Ключи, агрегаторы, кеши, порядок сериализации.
Желтый - классы представления. Цвет, шрифт, изображение.
Белый - вспомогательные классы для трансформации данных из одной формы в другую. Некий общий набор параметров между двумя слоями.

Нет никаких правил, описывающих количество слоев и способы именования. В рамках одного проекта возможно смешивание нескольких подходов. Идея простая, детали реализации одного слоя не должны влиять на детали реализации другого слоя.

Цитата Сообщение от limeniye Посмотреть сообщение
использую иммутабельный Dto-тип
Если класс называется Data Transfer Object, то и использовать его следует для этого же действия. Не надо надо добавлять суффикс Struct, любая ИДЕ умеет подсвечивать разными цветами классы, перечисления, интерфейсы, структуры... Не надо добавлять суффикс ReadOnly, выглядит дико, есть префикс immutable и не надо добавлять этот префикс/суффикс, когда все классы слоя такие.

Цитата Сообщение от limeniye Посмотреть сообщение
C#
1
[JsonProperty("id")]
Библиотека для JSON позволяет это выделять в отдельные файлы-конфигурации.

Цитата Сообщение от limeniye Посмотреть сообщение
проверить, какой из 10 новых студентов изменился и заменить его в списке
Если не подходит обновить весь список, то пройти по списку и сравнить свойства объектов.

Цитата Сообщение от limeniye Посмотреть сообщение
- банально перевести первую коллекцию в тип второй коллекции, а потом их сравнить(но мне кажется это слишком дорого).
- попробовать помудрить что-то с хешами.
А не дорого потом будет поддерживать хитрые хеши по всем свойствам или производительную замену измененных объектов?
2
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 10:20  [ТС]
А не дорого потом будет поддерживать хитрые хеши по всем свойствам или производительную замену измененных объектов?
I2um1, вот не знаю. На то и интересуюсь. Боюсь, что конвертация списка одного типа в другой — затратно. Хотел бы как-то уменьшить вес этого действия, даже если частично.
0
Злой няш
 Аватар для I2um1
2136 / 1505 / 565
Регистрация: 05.04.2010
Сообщений: 2,881
24.08.2021, 11:02
Цитата Сообщение от limeniye Посмотреть сообщение
Боюсь, что конвертация списка одного типа в другой — затратно
Расплата за более читаемый код. Самый простой вариант решения: хранить дату изменения. Хеш же лучше создавать автоматической генерацией кода на случай, когда количество свойств может измениться в будущем. В C# 10 в ноябре добавят struct record.
2
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 11:10  [ТС]
Цитата Сообщение от I2um1 Посмотреть сообщение
Самый простой вариант решения: хранить дату изменения
Звучит не плохо, но не реализуемо в моём решении.
Дело в том, что при такой реализации информация о последнем изменении должна приходить с сервера. Ибо я сравниваю ту информацию, которая пришла с сервера с той, которая есть.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 20:57
Цитата Сообщение от limeniye Посмотреть сообщение
Я вижу тут 2 решения:
Чё-то не догоняю проблемы.

Может, что-то не так понял из ваших объяснений.

Пишу в меру того как понял - если чё поправите.

По идее у вас должен быть в Модели словарь
C#
1
readobly Dictionary<string, StudentReadOnlyStruct> students = new Dictionary<string, StudentReadOnlyStruct>();
Добавление/изменение в словарь происходит ТОЛЬКО через подобные методы:
C#
1
2
void AddStudent(StudentReadOnlyStruct student) => students.Add(student.Id, student);
void SetStudent(StudentReadOnlyStruct student) => students[student.Id] = student;
То есть нужно обеспечить СТРОГОЕ соответствие ключа словаря Id студента.
Можно, при желании, под это сделать и какой-то специальный тип словаря, чтобы не повторять каждый раз кучу кода.


Теперь вам Репозиторий возвращает последовательность Студентов DTO.
Так как значение словаря значимый тип, то работа со словарём будет не очень оптимальной.
Что, впрочем, для несильно нагруженного приложения значения практически не имеет.

Метод для обработки словаря:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void AddOrReplaceStudents(IEnumerable<StudentReadOnlyStruc> receivedStudents)
{
    List<StudentReadOnlyStruc> newStudents = new List<StudentReadOnlyStruc>();
    List<StudentReadOnlyStruc> oldStudents = new List<StudentReadOnlyStruc>();
 
    foreach(var newStudent in receivedStudents)
    {
         if(students.TryGetVlue(student.id, out var oldStudent))
         {
             if (!EqulsStudents(newStudent, oldStudent))
             {
                  oldStudents.Add(oldStudent); 
                  newStudents.Add(newStudent); 
                  students[student.id] = newStudent;
             }
         }
         else
        {
              newStudents.Add(newStudent); 
              students.Add(student.id, newStudent);
         }
     }
 
    // После обработки - поднятие события уведомляющего об изменении
    // состояния Модели.
    if (newStudents.Count != 0 || oldStudents.Count != 0)
          RaiseStudentsChanged(oldStudents, newStudents);
}
 
// Этот метод может быть определён в StudentReadOnlyStruc 
// через интерфейс IEquatable<StudentReadOnlyStruc> 
bool EqulsStudents(StudentReadOnlyStruc first, StudentReadOnlyStruc second)
    => first.Id == second.Id &&
       first.Name = second.Name;
Добавлено через 10 минут
Дополненный тип:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    readonly public struct StudentReadOnlyStruct : IEquatable<StudentReadOnlyStruc>
    {
        public string Id { get; }
        public string Name { get; }
 
        private readonly int hash;
 
        public StudentReadOnlyStruct(string id, string name)
        {
            Id = id ?? string.Empty;
            Name = name ?? string.Empty;
            hash = Id.GetHashCode() ^ Name.GetHashCode();
        }
 
        public bool Equals(StudentReadOnlyStruct other)
            => Id == other.Id &&
               Name = other.Name;
 
       public override bool Equals(object obj)
           => obj is StudentReadOnlyStruct student &&
              Equals(student);
 
       public override int GetHashCode() => hash;
    }
Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Боюсь, что конвертация списка одного типа в другой — затратно. Хотел бы как-то уменьшить вес этого действия, даже если частично.
Если у вас не будет миллионов экземпляров, то даже не задумывайтесь над этим.

А если будет настолько нагруженная система (допустим обработка данных Вузов всей страны), то по любому домашний комп это не потянет.

Добавлено через 8 минут
Цитата Сообщение от limeniye Посмотреть сообщение
Звучит не плохо, но не реализуемо в моём решении.
Дело в том, что при такой реализации информация о последнем изменении должна приходить с сервера. Ибо я сравниваю ту информацию, которая пришла с сервера с той, которая есть.
Обычно с сервера данные должны приходить со штампом времени.
НО!

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

Во вторых, типы репозитория инкапсулированы в нём, и для того чтобы репозиторий проверил какую часть своих типов надо конвертировать в типы Модели (у вас это DTO. но это не обязательно - по идее должны быть Бизнес Сущности), Репозиторий должен "залезть" в данные Модели, что тоже не есть хорошо.
Это возможно только если Репозиторий не выделен из Модели.
Поэтому второй конвертацию из типов Репозитория в Бизнес Сущности, без нарушения архитекторы, тоже никак не получится избежать.
Или там таких "мин" можно самому себе понаставить...

Добавлено через 1 минуту
Поэтому штамп времени - это значение упрощающее валидацию, сравнение, но не заменяющее конвертации.

Добавлено через 5 минут
Допустим, при каждом изменении таблицы корректируется её штамп времени.
Пришли данные из этой таблицы.
Они сопровождаются штампом времени самой таблицы.
Вы его проверили - если совпадает со последним обработанным, то игнорируете все остальные присланные данные.
Но если штамп времени будет на каждой записи, то сравнение придётся производить в Модели.
А для этого придётся сначала сделать две конвертации.
Или хранить два экземпляра типов: типы Репозитория и Бизнес Сущности.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 20:59  [ТС]
Если у вас не будет миллионов экземпляров, то даже не задумывайтесь над этим.
Хорошо, а то я очень переживаю по этому поводу и стараюсь всё вместить в одну итерацию магическим образом.


Элд Хасп, выглядит не плохо, но я сомневаюсь касательно следующей ситуации:

1. В списке A следующий набор: { "Кирилл, 5 лет" , "Иван, 56 лет", "Юлия, бессмертный ангел" }
2. В списке Б следующий набор: { "Арсений, 13 лет" , "Иван, 56 лет", "Юлия, бессмертный ангел" }
3. Список Б — это новый ответ от сервера, в котором уже нет Кирилла и появился Арсений. А это, получается, ещё одна итерация.

Из предложенной Вами реализации, я так понимаю, мне нужно создать третий список, для элементов, которые есть в старом списке, но которых нет в новом ( чтобы удалить их и вызвать событие).
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 21:09
Цитата Сообщение от limeniye Посмотреть сообщение
Из предложенной Вами реализации, я так понимаю, мне нужно создать третий список, для элементов, которые есть в старом списке, но которых нет в новом ( чтобы удалить их и вызвать событие).
ДА.
Так как Модель должна извещать об изменении своего состояния.
В общем случае зависит от того как у вас реализованы события.
Если изменения относительно редкие, единичные, то можно подымать событие при изменение каждого элемента - тогда список не нужен.
Но если изменения в основном пакетные, то лучше обработать сразу весь пакет и поднять одно событие для всего пакета.
А это без накопления списков удаляемых и добавляемых не выйдет.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
А это, получается, ещё одна итерация.
Нет.
Посмотрите внимательнее код.
Для каждого элемента полученного списка выполняется единичный поиск в словаре.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 21:47  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Так как значение словаря значимый тип, то работа со словарём будет не очень оптимальной.
Что тут имеется ввиду? Я наоборот решил "оптимизировать" код, чтобы не искать из кучи, а сразу иметь значимый тип: "вот он, беирте", а не "он где-то гуляет, поищите за домом".

Добавлено через 2 минуты
Вообще, мне известно количество элементов(пользователь выбирает сколько элементов он хочет получить: 20, 30...), поэтому я тут подумываю всё на массиве сделать.

Добавлено через 22 минуты
Вообще стоит ли, в данной ситуации, использовать массивы (в чистом виде)? Допустим у пользователя есть ComboBox, в котором он выбрал: "показать 20 элеметов" и я знаю, что элементов будет 20. Есть ли у массива StudentDto[] преимущества перед конкурентами: IReadOnlyCollection<StudentDto>; IList<StudentDto> и IDictionary<long, Student> и т.д.?

Какой, в данном случае, самый оптимальный подход, при условии самый ТС задачи?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 21:51
Цитата Сообщение от limeniye Посмотреть сообщение
Что тут имеется ввиду? Я наоборот решил "оптимизировать" код, чтобы не искать из кучи, а сразу иметь значимый тип: "вот он, беирте", а не "он где-то гуляет, поищите за домом".
Когда значение возвращается в методе TryGetValue - происходит одни поиск.
Когда оно заменяется students[student.id] = newStudent; - происходит второй поиск.

Если бы это был ссылочный тип: class entity {StudentReadOnlyStruct student}.
То второго поиска можно было избежать:
C#
8
9
10
11
12
13
14
15
16
         if(students.TryGetVlue(student.id, out var ent))
         {
             if (!EqulsStudents(newStudent, ent.student))
             {
                  oldStudents.Add(ent.student); 
                  newStudents.Add(newStudent); 
                  ent.student = newStudent;
             }
         }

Сказать что лучше, без тестирования на реальных данных не возможно.
И нужно создавать очень критические условия для тестов, так как на обычной типовой нагрузке вряд ли получится определить разницу.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Вообще, мне известно количество элементов(пользователь выбирает сколько элементов он хочет получить: 20, 30...), поэтому я тут подумываю всё на массиве сделать.
Так как для десериализованных данных роль ссылки на экземпляр играет Id, то лучше использовать словарь с ключом по идентификатору.
Иначе можно в лёгкую дров наломать.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 21:52  [ТС]
Элд Хасп,
И нужно создавать очень критические условия тесты, так на обычной типовой нагрузке вряд ли получится определить разницу.
Я понимаю, но я имею ввиду в рамках теоритических предложений.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 21:58
Цитата Сообщение от limeniye Посмотреть сообщение
Есть ли у массива StudentDto[] преимущества перед конкурентами: IReadOnlyCollection<StudentDto>; IList<StudentDto> и IDictionary<long, Student> и т.д.?
А каких преимуществах вы говорите при использовании WPF?
Там любой тип будет раз двадцать конвертирован, упакован-распакован.
На любое представление простейшего числа или строки требуется сотни, если не тысячи операций.

Такая оптимизация (по быстродействию) необходима только в случае очень нагруженной Бизнес Логики.

Для представление максимум что следует сделать, это не создавать огромного количества UI элементов.
Допустим передача коллекции из сотен элементов с десятком свойств в DataGrid может ощутимо подвесить GUI.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Я понимаю, но я имею ввиду в рамках теоритических предложений.
Бесполезно.
Имеет смысл, если вы оптимизируете суперкомпьютер обрабатывающий данные всей страны.

Если из любопытства, то надо делать тесты на реальных данных.
Теория здесь не поможет.
На разных данных, на разном железе может получить противоположные результаты.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 22:49  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Сообщение от limeniye
А это, получается, ещё одна итерация.
Нет.
Посмотрите внимательнее код.
Там в коде foreach(var newStudent in recivedStudents), но как я себе это представляю, чтобы проверить содержит ли новая коллекция элемент из старой коллекции, то для этого нужно будет foreach(var maybeDeletedStudent in students)


________________________________________ __________________


Добавлено через 13 секунд
Элд Хасп, начитался информации о том, какие же крутые Структуры и подумал: "тогда почему я всё ещё использую ссылчные типы?". Первое внедрение Значимого типа и уже дополнительная итерация где-то ) И уже никакая не оптимизация. Ох.

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

Давайте резюмирую:

- основное перечисление лучше хранить в словаре, "так как для десериализованных данных роль ссылки на экземпляр играет Id"

C#
1
2
3
4
5
6
7
IDictionary<long, StudentDto> students = new Dictionary<long, AdImmutable>();
IReadOnlyDictionary <long, StudentDto> Students { get; }
 
public UniversityRepository()
{
    Students = new ReadOnlyDictionary(students);
}
- а если мы работаем с словарём, то лучше использовать ссылочные типы. Также, для удобства сравнения используем хеши:
(и так как Id типа long, убрал проверку на null)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    public class StudentDto : IEquatable<StudentDto>
    {
        public long Id { get; }
        public string Name { get; }
 
        private readonly int hash;
 
        public StudentDto(long id, string name)
        {
            Id = id;
            Name = name ?? string.Empty;
            hash = Id.GetHashCode() ^ Name.GetHashCode();
        }
 
        public bool Equals(StudentDto other)
            => Id == other.Id &&
               Name = other.Name;
 
       public override bool Equals(object obj)
           => obj is StudentDto student &&
              Equals(student);
 
       public override int GetHashCode() => hash;
    }

- определяемся с тем, как много элементов будут изменены за раз. В моём случае нет смысла в событии передавать коллекцию, я думаю будет достаточно передать элемент и его событие. Благо у меня есть Ваша реализация этой задачи:

Реализация поднятия события изменения значения в словаре. Взято у Элд Хасп,
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    public enum NotifyDictionaryChangedAction
    {
        /// <summary>Добавлен новый ключ.</summary>
        Added,
        /// <summary>Удалён ключ.</summary>
        Removed,
        /// <summary>Изменено значение для ключа.</summary>
        Changed
    }
    /// <summary>Аргументы события изменения словаря.</summary>
    /// <typeparam name="TKey">Тип ключа словаря.</typeparam>
    /// <typeparam name="TValue">Тип значения словаря.</typeparam>
    public class NotifyDictionaryChangedEventArgs<TKey, TValue> : NotifyActionDictionaryChangedEventArgs
    {
 
        /// <summary>Ключ в отношении которого произведено действие.</summary>
        public TKey Key { get; }
 
        /// <summary>Удаляемое или измененое значение.</summary>
        public TValue OldValue { get; }
 
        /// <summary>Добавленное или новое значение.</summary>
        public TValue NewValue { get; }
 
        public NotifyDictionaryChangedEventArgs(NotifyDictionaryChangedAction action, TKey key, TValue oldValue, TValue newValue)
            : base(action)
        {
            Key = key;
            OldValue = oldValue;
            NewValue = newValue;
        }
 
    }
 
    /// <summary>Аргументы события изменения словаря. 
    /// Содержит только действие и метод создания экземпляров производных классов.</summary>
    public class NotifyActionDictionaryChangedEventArgs : System.EventArgs
    {
        /// <summary>Действие изменившее словарь.</summary>
        public NotifyDictionaryChangedAction Action { get; }
 
        /// <summary>Создаёт экземпляр.</summary>
        /// <param name="action">Действие изменившее словарь.</param>
        public NotifyActionDictionaryChangedEventArgs(NotifyDictionaryChangedAction action)
        {
            Action = action;
        }
 
        public static NotifyDictionaryChangedEventArgs<TKey, TValue> AddKey<TKey, TValue>(TKey key, TValue value)
          => new NotifyDictionaryChangedEventArgs<TKey, TValue>(NotifyDictionaryChangedAction.Added, key, default, value);
        public static NotifyDictionaryChangedEventArgs<TKey, TValue> RemoveKey<TKey, TValue>(TKey key, TValue value)
            => new NotifyDictionaryChangedEventArgs<TKey, TValue>(NotifyDictionaryChangedAction.Removed, key, value, default);
        public static NotifyDictionaryChangedEventArgs<TKey, TValue> ChangedValue<TKey, TValue>(TKey key, TValue oldValue, TValue newValue)
            => new NotifyDictionaryChangedEventArgs<TKey, TValue>(NotifyDictionaryChangedAction.Changed, key, oldValue, newValue);
    }


- в таком случае реализция будет выглядеть следущим образом:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void StudentsHandler(IEnumerable<StudentDto> receivedStudents)
{ 
    foreach(var newStudent in receivedStudents)
    {
         if(students.TryGetVlue(student.Id, out var ent))
         {
             if (!EqulsStudents(newStudent, ent.student))
             {
                  RaiseStudentsChange(ent.student, newStudent);
                  ent.student = newStudent;
             }
         }
         else
        {
              RaiseStudentsAdd(newStudent);
        }
     }
}
 
// TODO : переопределить в StudentDto
bool EqulsStudents(StudentDto first, StudentDto second)
    => first.Id == second.Id &&
       first.Name = second.Name;
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 23:03
Цитата Сообщение от limeniye Посмотреть сообщение
Там в коде foreach(var newStudent in recivedStudents), но как я себе это представляю, чтобы проверить содержит ли новая коллекция элемент из старой коллекции, то для этого нужно будет foreach(var maybeDeletedStudent in students)
Нет.
Вы проверяете только входящую коллекцию.
Каждый элемент сначала ищите такой же в существующей.
Если его нет то добавляете.
Если он есть, то проверяя обновился он или нет.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 23:08  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если его нет то добавляете.
Если он есть, то проверяя обновился он или нет.
Задача немного другая. Если в новой коллекции его нет, что и из основной он должен удалиться. В таком случае я использую дополнительную итерацию.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 23:34
Цитата Сообщение от limeniye Посмотреть сообщение
в таком случае реализция будет выглядеть следущим образом:
По принятым неписанным (а может и писанным) правилам, событие Changed происходит ПОСЛЕ изменения.
ДО ИЗМЕНЕНИЯ происходит событие Changing - такие используются, но редко и, сколько видел, всегда в паре с Changed.

Поэтому так:
C#
1
2
3
4
5
6
             if (!EqulsStudents(newStudent, ent.student))
             {
                  var old = ent.student;
                  ent.student = newStudent;
                  RaiseStudentsChanged(old, newStudent);
             }
Или так:
C#
1
2
3
4
5
6
7
             if (!EqulsStudents(newStudent, ent.student))
             {
                  var old = ent.student;
                  RaiseStudentsChanging(old, newStudent);
                  ent.student = newStudent;
                  RaiseStudentsChanged(old, newStudent);
             }
Добавлено через 1 минуту
Так же в событии Changing могут предусматриваться параметры для отмены присвоения, или изменения присваиваемого значения.

Добавлено через 7 минут
Цитата Сообщение от limeniye Посмотреть сообщение
Задача немного другая. Если в новой коллекции его нет, что и из основной он должен удалиться. В таком случае я использую дополнительную итерацию.
То есть у вас не обновление списка приходит, а новый список?
Обычно такое происходит только при подписке на Репозиторий.
А потом приходят обновления.

Если приходит всегда НОВЫЙ список, то не надо заморачиваться.
Просто создайте массив и отправьте его по событию.
В ViewModel нужна совсем иная оптимизация для уменьшения нагрузки на View.
Там ObservableCollection переписываете элементами из нового списка.
Лишние удаляете, нехватающие - добавляете.
Немного проблем доставит только. если в View предусмотрена обработка одного элемента и надо предусмотреть как должно отреагировать представление при смене коллекции в этом случае.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 23:35
Цитата Сообщение от limeniye Посмотреть сообщение
начитался информации о том, какие же крутые Структуры и подумал: "тогда почему я всё ещё использую ссылчные типы?"
Пример.
Создали массив ссылочного типа.
Это достаточно затрано.
Под каждый элемент выделяется место в куче.
Потом выделяется место под массив по 4 (или 8) байт под каждую ссылку на объект.

Для значимого типа, выделяется чуть меньшее место в стеке.
Но массив то сам ссылочного типа.
И значит место под ссылочный тип всё равно будет затребовано в куче.

Если нужно клонировать массив (при передаче в другой метод, в ругой слой и т.д.), то для ссылочного типа будут копироваться только ссылки на объекты.
А для значимого - целиком весь массив.

То есть нет общего правила на все случаи жизни.
Всё зависит от конкретной задачи.

Другой пример.
Если у вас в структуре поля ТОЛЬКО значимого типа.
То тогда не нужно реализовывать Equals и GetHasCode - хватает реализации по умолчанию.

Но если в структуре есть поля ссылочного типа, даже если они иммутабельные (как у вас строка Name), то реализации по умолчанию Equals и GetHasCode будут учитывать только ссылку в поле.
И может быть ситуация когда одинаковые Name, но полученные разными способами для дефолтных Equals и GetHasCode не будут считаться равными.
Поэтому, если есть ссылочные поля в структуре и нужно сравнение по значению, то нужна собственная реализация Equals и GetHasCode.

В целом, такое заключение.
Если в типе поля ТОЛЬКО значимого типа, то с большой вероятностью этот тип получится удачно реализовать как структуру.
Если в типе есть поля ссылочного типа, то удобство реализации и использования структуры резко снижается.
И надо рассматривать уже по многим параметрам и конкретным условиям задания.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
24.08.2021, 23:48  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Для значимого типа, выделяется чуть меньшее место в стеке.
Но массив то сам ссылочного типа.
И значит место под ссылочный тип всё равно будет затребовано в куче.
Если тип содержит только значимые поля/свойства, то в теории можно использовать struct, но если подразумевается, что в дальнейшем он будет использоваться в массиве, то в таком случае лучше использовать ссылочныйы тип, даже есть все его свойства значимые. Верно?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 23:51
limeniye, простые структуры сейчас очень успешно во многих случаях могут заменить кортежи.
Это значимы мутабельный тип.
Но мутабельность значимых типов несоздаёт проблем, поскольку после копирования копия не связана с оригиналам.

Допустим:
C#
1
2
3
4
5
Paint a = new Point(1,2);
Point b = a;
b.X = 10;
 
Console.Write(a.X);
Если Point значимый тип, то вывод будет 1. Как было это значение записано так оно и осталось.
А для ссылочного типа, вывод будет 10.
Что не всегда очевидно.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
24.08.2021, 23:57
Цитата Сообщение от limeniye Посмотреть сообщение
но если подразумевается, что в дальнейшем он будет использоваться в массиве, то в таком случае лучше использовать ссылочныйы тип
С массивами (коллекциями) много своих нюансов.
Однозначного ответа нет.

Допустим, есть массив Point[].
Вам нужно изменить X у первого элемента.
Если это ссылочный тип, то это points[0].X = 12;.
Если значимый, то - points[0] = new Point(12, point[0].Y) - то есть нужно заменять полностью весь экземпляр.
С одной стороны это не удобно.

Но посмотрите с точки зрения WPF.
Если ссылочного, то нужно в типе элемента Point - реализация INPC.
А для значимого - не нужно.
Так как элемент заменяется всегда только полностью, то достаточно ObservableCollection.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
24.08.2021, 23:57
Помогаю со студенческими работами здесь

Преобразование типов....
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using...

Преобразование типов
Есть метод, который принимает на вход переменную типа IEnumerable&lt;DataRow&gt;; у меня есть datagridView. Могу ли я коллекцию строк...

Преобразование типов
Всем привет. Переношу код из сишной реализации в проект на C#. Есть функция подсчета CRC, при ее переносе компилятор выдает ошибки. ...

Преобразование типов
Код: using System; using System.Text; public class Program { public static void Main(string args) { string...

Преобразование типов
Всем привет, не получается преобразовать начальное значение т.е. инициализация переменной класса. По сути все значения в классе string...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
1С: Контроль уникальности заводского номера
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью. Данные берутся из регистра сведений, по которому настроено. . .
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru