如何比较具有相似属性的两个截然不同的对象

这完全在C#中,使用.NET 2.0。

我有两个对象列表。 它们不是相关对象,但它们确实具有可以比较的某些共同点,例如基于Guid的唯一标识符。 这两个列表需要由另一个列表过滤,该列表只包含Guid,它可能与前两个列表中包含的ID匹配,也可能不匹配。

我已经想过将每个对象列表转换为’对象’并按此排序的想法,但是我不确定一旦它被转换我将能够访问ID属性,并且我在想这个方法在知道要排序的列表是什么时,对两个列表进行排序应该有些愚蠢。

引入每个对象列表的最佳方法是什么,以便可以仅使用ID来对列表进行排序?

您应该使每个不同的对象实现一个公共接口。 然后为该接口创建IComparer 并在排序中使用它。

好的,如果您有权修改原始类只是为了在那里添加界面,马修就把它发现了。 我在这里有点疯狂,并使用2.0匿名代表定义了一个完整的解决方案。 (我想我沉迷于3.0 Lambda;否则,如果我还在使用2005,我可能会在foreach循环中写出来)。

基本上,使用公共属性创建一个接口。 让yoru两个类实现接口。 创建一个作为接口输入的公共列表,将值转换并将其翻录到新列表中; 删除任何不匹配的项目。

//Program Output: List1: 206aa77c-8259-428b-a4a0-0e005d8b016c 64f71cc9-596d-4cb8-9eb3-35da3b96f583 List2: 10382452-a7fe-4307-ae4c-41580dc69146 97f3f3f6-6e64-4109-9737-cb72280bc112 64f71cc9-596d-4cb8-9eb3-35da3b96f583 Matches: 64f71cc9-596d-4cb8-9eb3-35da3b96f583 Press any key to continue . . . using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication8 { class Program { static void Main(string[] args) { //test initialization List list1 = new List(); List list2 = new List(); ClassTypeA citem = new ClassTypeA(); ClassTypeB citem2 = new ClassTypeB(); citem2.ID = citem.ID; list1.Add(new ClassTypeA()); list1.Add(citem); list2.Add(new ClassTypeB()); list2.Add(new ClassTypeB()); list2.Add(citem2); //new common list. List common_list = new List(); //in english, give me everything in list 1 //and cast it to the interface common_list.AddRange( list1.ConvertAll(delegate( ClassTypeA x) { return (ICommonTypeMakeUpYourOwnName)x; })); //in english, give me all the items in the //common list that don't exist in list2 and remove them. common_list.RemoveAll(delegate(ICommonTypeMakeUpYourOwnName x) { return list2.Find(delegate(ClassTypeB y) {return y.ID == x.ID;}) == null; }); //show list1 Console.WriteLine("List1:"); foreach (ClassTypeA item in list1) { Console.WriteLine(item.ID); } //show list2 Console.WriteLine("\nList2:"); foreach (ClassTypeB item in list2) { Console.WriteLine(item.ID); } //show the common items Console.WriteLine("\nMatches:"); foreach (ICommonTypeMakeUpYourOwnName item in common_list) { Console.WriteLine(item.ID); } } } interface ICommonTypeMakeUpYourOwnName { Guid ID { get; set; } } class ClassTypeA : ICommonTypeMakeUpYourOwnName { Guid _ID; public Guid ID {get { return _ID; } set { _ID = value;}} int _Stuff1; public int Stuff1 {get { return _Stuff1; } set { _Stuff1 = value;}} string _Stuff2; public string Stuff2 {get { return _Stuff2; } set { _Stuff2 = value;}} public ClassTypeA() { this.ID = Guid.NewGuid(); } } class ClassTypeB : ICommonTypeMakeUpYourOwnName { Guid _ID; public Guid ID {get { return _ID; } set { _ID = value;}} int _Stuff3; public int Stuff3 {get { return _Stuff3; } set { _Stuff3 = value;}} string _Stuff4; public string Stuff4 {get { return _Stuff4; } set { _Stuff4 = value;}} public ClassTypeB() { this.ID = Guid.NewGuid(); } } } 

仅使用.NET 2.0方法:

 class Foo { public Guid Guid { get; } } List GetFooSubset(List foos, List guids) { return foos.FindAll(foo => guids.Contains(foo.Guid)); } 

如果您的类没有实现公共接口,则必须GetFooSubset为每种类型实现GetFooSubset

我不确定我是否完全理解你想要的东西,但你可以使用linq从列表中选择匹配的项目以及对它们进行排序。 这是一个简单的示例,其中一个列表中的值在另一个列表上进行过滤并进行排序。

  List itemList = new List() { 9,6,3,4,5,2,7,8,1 }; List filterList = new List() { 2, 6, 9 }; IEnumerable filtered = itemList.SelectMany(item => filterList.Where(filter => filter == item)).OrderBy(p => p); 

我还没有机会使用AutoMapper,但根据您的描述,您希望查看它 。 来自Jimmy Bogard的post:

AutoMapper约定

由于AutoMapper变平,它将寻找:

匹配属性名称

嵌套属性名称(Product.Name通过假定PascalCase命名约定映射到ProductName)

方法以“Get”开头,因此GetTotal()映射到Total

已配置任何现有类型映射

基本上,如果删除了所有“点”和“获取”,AutoMapper将匹配属性名称。 目前,AutoMapper不会因类型不匹配而失败,但出于其他原因。

我不完全确定你想要的最终结果,但….

如果要比较两种不同类型的属性,可以将属性名称和相应的值投影到两个词典中。 并且利用该信息对属性值进行某种排序/差异。

  Guid newGuid = Guid.NewGuid(); var classA = new ClassA{Id = newGuid}; var classB = new ClassB{Id = newGuid}; PropertyInfo[] classAProperties = classA.GetType().GetProperties(); Dictionary classAPropertyValue = classAProperties.ToDictionary(pName => pName.Name, pValue => pValue.GetValue(classA, null)); PropertyInfo[] classBProperties = classB.GetType().GetProperties(); Dictionary classBPropetyValue = classBProperties.ToDictionary(pName => pName.Name, pValue => pValue.GetValue(classB, null)); internal class ClassB { public Guid Id { get; set; } } internal class ClassA { public Guid Id { get; set; } } classAPropertyValue Count = 1 [0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]} classBPropetyValue Count = 1 [0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]} 

这本质上应该可以让你得到你想要的东西 – 但你可能更善于使用linq

 class T1 { public T1(Guid g, string n) { Guid = g; MyName = n; } public Guid Guid { get; set; } public string MyName { get; set; } } class T2 { public T2(Guid g, string n) { ID = g; Name = n; } public Guid ID { get; set; } public string Name { get; set; } } class Test { public void Run() { Guid G1 = Guid.NewGuid(); Guid G2 = Guid.NewGuid(); Guid G3 = Guid.NewGuid(); List t1s = new List() { new T1(G1, "one"), new T1(G2, "two"), new T1(G3, "three") }; List filter = new List() { G2, G3}; List filteredValues1 = t1s.FindAll(delegate(T1 item) { return filter.Contains(item.Guid); }); List filteredValues2 = t1s.FindAll(o1 => filter.Contains(o1.Guid)); } }