Возвращает один объект из списка объектов C#, проверяя соответствие свойств

У меня есть требование создать объект "фабрика", который работает следующим образом:

  1. Принимает список совпадающих типов объектов.
  2. Сравнивает каждое значение свойства в списке, чтобы увидеть, совпадают ли они.
  3. Возвращает новый единственный экземпляр этого типа объекта только с набором совпадающих полей.

(Для простоты мы можем предположить, что все свойства являются строками)

Например, из этого списка объектов-лиц:

Person1 { Name: "Bob", Job: "Policeman", Location: "London" }
Person2 { Name: "John", Job: "Dentist", Location: "Florida" }
Person3 { Name: "Mike", Job: "Dentist", Location: "London"  }
Person4 { Name: "Fred", Job: "Doctor", Location: "London"   }

Если бы я передал список, содержащий людей 2 и 3, он вернул бы нового человека следующим образом:

Name: "No Match", Job: "Dentist", Location "No Match"

Если бы я прошел через человека 3 и 4, он вернул бы нового человека:

Name: "No Match", Job: "No Match", Location "London"

Уже....
Используя ответ на этот вопрос SO :
Как проверить, имеют ли все элементы списка одинаковое значение, и вернуть его или вернуть «другое значение», если это не так?

Я могу заставить этот LINQ работать с одним известным объектом, но мне нужно, чтобы он был универсальным. Это охватывает только одно конкретное свойство, но мои объекты имеют более 30 свойств.

var otherValue = "No Match"
var matchingVal= people.First().Job;
return people.All(x=>x.Job== matchingVal) ? matchingVal: otherValue; 

Я также знаю, что могу использовать отражение, чтобы получить список свойств в моем объекте. Но как все это совместить в одну «фабрику» — непостижимо.

Я не думаю, что это уникальная проблема, но я не могу найти полное решение ни в одном из моих поисков. Может быть, уже есть пакет Nuget, который может мне помочь?

Все советы с благодарностью получил.

Какие типы свойств должны поддерживаться (например, строка, int, DateTime, классы). Что в вашем примере с идентификатором свойства? Как метод узнает, какие свойства следует сравнивать?

Oliver 16.03.2022 10:30

@Oliver Идентификатор был просто для ссылки в моем примере. Я изменил его, чтобы было понятнее. Все свойства должны быть сопоставлены.

Bandito 16.03.2022 10:41

Где для каждого типа определено, что должно быть вставлено, если совпадение не найдено (например, int = -1, string = null или string = «нет совпадения», DateTime = DateTime.MaxValue и т. д.)

Oliver 16.03.2022 10:41

Мы можем рассматривать все как строку. Поэтому, если строки совпадают, новый объект будет иметь это значение. Если они этого не делают, новый объект получает произвольное значение в этом свойстве, например: «Нет совпадения».

Bandito 16.03.2022 10:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш ввод представляет собой перечисление объектов определенного типа, и вы должны создать объект того же типа, где все свойства заполнены, где все значения одинаковы. Это можно сделать примерно так:

private static T GetCommonProperties<T>(IEnumerable<T> source) where T : new()
{
    var first = true;
    var common = new T();
    var props = typeof(T).GetProperties();

    foreach (var item in source)
    {
        if (first)
        {
            first = false;

            foreach (var prop in props)
            {
                var value = prop.GetValue(item, null);
                prop.SetValue(common, value);
            }
        }
        else
        {
            foreach (var prop in props)
            {
                var itemValue = prop.GetValue(item, null);
                var commonValue = prop.GetValue(common, null);

                if ((dynamic)itemValue != (dynamic)commonValue)
                {
                    prop.SetValue(common, GetDefault(prop.PropertyType));
                }

            }
        }
    }

    return common;
}

Данный метод на самом деле не является оптимальным, поскольку он использует трюк dynamic для решения проблемы сравнения значений в коробках. Кроме того, получение значения по умолчанию для определенного типа, вероятно, может быть реализовано с помощью этого общего подхода:

private static object GetDefault(Type t)
{
    return typeof(Program)
        .GetMethod(nameof(GetDefaultValue), BindingFlags.NonPublic | BindingFlags.Static)
        .MakeGenericMethod(t)
        .Invoke(null, null);
}

private static T GetDefaultValue<T>()
{
    return default;
}

Но также можно было бы предоставить оператор switch или Dictionary<Type, object>, который возвращает желаемое значение по умолчанию, если совпадение отсутствует.

И последнее, но не менее важное: еще одним возможным улучшением производительности будет удаление всех записей PropertyInfo из переменной props, потому что для любого следующего предстоящего объекта эта проверка больше не нужна, и точно так же цикл может быть досрочно завершен, когда больше нет реквизитов. доступны больше.

Рабочий пример можно найти здесь.

Ух ты! @ Оливер, это именно то, что мне нужно. Большое спасибо, что нашли время и предоставили такое комплексное решение.

Bandito 16.03.2022 14:28

Рад слышать. Тем не менее, вам, вероятно, следует реализовать упомянутые улучшения, особенно если вы вызываете эту вещь очень часто, в циклах или с большим количеством элементов в исходном коде.

Oliver 16.03.2022 16:11

Верно подмечено. Спасибо еще раз.

Bandito 16.03.2022 22:40

Другие вопросы по теме