Как использовать Reflection для кондиционирования нескольких свойств для проверки равенства в операторе LINQ .Where, в зависимости от того, какой класс передается? - PullRequest
2 голосов
/ 08 июля 2019

Я пытаюсь обобщить дублирующую функцию проверки, которая в зависимости от того, какой тип объекта проверяет свойства, указанные в классе (предоставленные в конфигурации), равны свойствам в другом списке.

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

Пример словаря enties:

"Book", ["Title", "CoverImage", "NumberOfPages"] 
"Author", ["Name", "Address", "SomethingElse"]

Затем я передаю объект функции и использую Reflection, чтобы получить имя типа ...

obj.GetType().Name;

... которое язатем используйте для получения правильного KVP из Словаря, что означает, что если я передам объект Book, я получу «Book».Затем мы используем это, чтобы получить конфигурацию через ...

configDictionary["obj.GetType().Name"]

..., которая дает нам массив строк, которые являются свойствами, с которыми нам нужно проверить равенство.

Iя попал в ту часть, где мне нужно что-то вроде

list.Where(x => --> for each of the strings in the array - x.GetType.GetProperty(string) && --> same for next string && same for next string

... и затем мне нужно завершить это ...

x.Id != obj.Id

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

Конечный запрос должен выглядеть следующим образом:

Books:

someList.Where(x => 
x.Title == obj.Title 
&& x.CoverImage == obj.CoverImage 
&& x.NumberOfPages == obj.NumberOfPages 
&& x.Id != obj.Id)
.FirstOrDefault();

Авторы:

someList.Where(x => x.Name == obj.Name 
&& x.Address == obj.Address 
&& x.SomethingElse == obj.SomethingElse 
&& x.Id != obj.Id)FirstOrDefault();

Ответы [ 2 ]

2 голосов
/ 08 июля 2019

Старайтесь избегать рефлексии, потому что это может замедлить ваше приложение.В качестве альтернативы вы можете создать словарь и поместить в него все компараторы:

var configDictionary = new Dictionary<string, List<Func<object, object, bool>>>
{
    {
        "Book",
        new List<Func<object, object, bool>>
        {
            (b1, b2) => ((Book)b1).Title == ((Book)b2).Title,
            (b1, b2) => ((Book)b1).CoverImage == ((Book)b2).CoverImage,
            (b1, b2) => ((Book)b1).NumberOfPages == ((Book)b2).NumberOfPages,
            (b1, b2) => ((Book)b1).Id != ((Book)b2).Id,
        }
    },
    // same for Authors
};

Теперь вы можете использовать его в методе Where:

var typeName = obj.GetType().Name; // here we using Reflection but once per collection, not per each item
var first = someList.Where(x => configDictionary[typeName].All(f => f(x, obj))).FirstOrDefault();

Также, потому что FirstOrDefaultтакже есть перегрузка, которая принимает предикат последней строки, которая может быть переписана в:

var first = someList.FirstOrDefault(x => configDictionary[typeName].All(f => f(x, obj)));
0 голосов
/ 08 июля 2019

Лучшим решением будет создание пользовательского атрибута, который будет помечать свойство. Затем в классе переопределите метод по умолчанию Equals, который получит все свойства с этим атрибутом и вернет равенство.

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