如何使用反射来调节多个属性以在linq的语句中检查平等,具体取决于传递的类别?[英] How use Reflection to condition multiple properties to check for equality in a LINQ .Where statement, depending on what class is passed?

本文是小编为大家收集整理的关于如何使用反射来调节多个属性以在linq的语句中检查平等,具体取决于传递的类别?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在尝试概括一个重复的检查器函数,该功能取决于对象的类型,检查属性所述类(以配置中提供)等于另一个列表中的属性.

我已决定创建一个词典,该字典将接受键的类型字符串(书籍,作者,商店等)以及一系列需要相等的属性.

字典的示例Ente:

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

然后,我将对象传递到功能,并使用反射以获取类型的名称...

obj.GetType().Name;

...然后我用来从字典中获取正确的KVP,这意味着如果我通过书对象,我会得到"书".然后,我们使用它来通过...

获得配置
configDictionary["obj.GetType().Name"]

...为我们提供了一系列的字符串,这些字符串是我们需要检查平等的属性.

我已经进入了我需要

的东西的部分
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

确保我们基于逻辑(所有属性的不同ID和匹配,但具有不同的ID)检查重复项.

).

最终查询应该看起来像

书籍:

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();

推荐答案

尝试避免反射,因为它可以减慢您的应用程序.作为替代方案,您可以创建一个字典并将所有比较器放入其中:

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();
var first = someList.FirstOrDefault(x => configDictionary[typeName].All(f => f(x, obj)));

其他推荐答案

更好的解决方案将是创建将标记属性的自定义属性.然后在类中覆盖默认方法等于,它将获得此属性并返回平等的所有属性.

本文地址:https://www.itbaoku.cn/post/1556801.html

问题描述

I'm trying to generalize a duplicate checker function, which depending on which type of object, checks the properties said class has (provided in a configuration) are equal to those in another list.

I have decided to create a Dictionary, which will accept a type string for the key (Book, Author, Shop, etc.) and an array of properties that need to be equal.

Example of Dictionary enties:

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

Then, I pass an object to the function and use Reflection to get the name of the type...

obj.GetType().Name;

... which I then use to fetch the right KVP from the Dictionary, meaning that if I pass a Book object, I get "Book". We then use that to get the configuration via ...

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

... which gives us the array of strings that are the properties that we need to check equality on.

I've gotten to the part where I need something along the lines of

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

... and then I need to top it off with an...

x.Id != obj.Id

To make sure we check for duplicates based on our logic (different id's and matches on all properties but has different Id's thus - a duplicate).

The end query should look like

Books:

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

Authors:

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

推荐答案

Try to avoid reflection because it can slow down your application. As an alternative you can create a dictionary and put all comparators into it:

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
};

Now you can use it in Where method:

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();

Also, because FirstOrDefault also has overload that accept predicate last line can be rewritten to:

var first = someList.FirstOrDefault(x => configDictionary[typeName].All(f => f(x, obj)));

其他推荐答案

A better solution will be creating custom attribute which will tag property. Then in class override default method Equals which will get all properties with this attribute and return equality.