问题描述
我正在尝试概括一个重复的检查器函数,该功能取决于对象的类型,检查属性所述类(以配置中提供)等于另一个列表中的属性.
我已决定创建一个词典,该字典将接受键的类型字符串(书籍,作者,商店等)以及一系列需要相等的属性.
字典的示例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)));
其他推荐答案
更好的解决方案将是创建将标记属性的自定义属性.然后在类中覆盖默认方法等于,它将获得此属性并返回平等的所有属性.
问题描述
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.