2009-11-12 81 views
5

这是使用.NET 2.0的C#中的所有内容。如何比较具有相似属性的两个明显不同的对象

我有对象的两个列表。它们不是相关的对象,但它们确实有一些共同点,比如基于Guid的独特标识符。这两个列表需要 由只包含的GUID另一个列表可能会或可能不会与 匹配过滤的ID的包含在第一个两个列表。

我曾经想过把每个对象列表转换为'对象'并按 排序的想法,但我不确定一旦它被投射就能够访问ID属性, m 认为排序这两个列表的方法在知道要排序的列表是什么时应该有点愚蠢。

什么是每个对象名单带来,以便它可以对列表中只用ID的排序的最佳方式?

+0

排序或过滤?按什么排序? – dtb 2009-11-12 21:00:23

+0

实际过滤。 object.GuidId == list.GuidId返回对象。 – Chris 2009-11-12 21:14:08

回答

15

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

+3

如果您可以实现一个通用接口(因为您不拥有一个或两个对象),您将需要制作实现通用接口的适配器类。那么你是金。 – plinth 2009-11-12 21:35:15

+0

换句话说,你基本上是将每个对象转换为包含两者共同元素的类(接口)类型,然后比较结果(相同类型)的对象。使用接口可以避免显式的转换操作。 – 2009-11-12 22:20:17

+0

我觉得像Jimmy的AutoMapper这样的东西能够为相关对象类型注册类似IComparer的类将会很有趣。思考? – 2014-11-14 18:42:13

0

我不知道我完全理解你想要什么,但你可以使用LINQ选择了从列表中匹配的项目,以及对它们进行排序。下面是一个简单的例子,其中一个列表中的值在另一个列表中被过滤并排序。

 List<int> itemList = new List<int>() { 9,6,3,4,5,2,7,8,1 }; 
     List<int> filterList = new List<int>() { 2, 6, 9 }; 

     IEnumerable<int> filtered = itemList.SelectMany(item => filterList.Where(filter => filter == item)).OrderBy(p => p); 
0

我还没有机会使用AutoMapper呢,但是从你的描述你希望check it out。从吉米·博加德的帖子:

AutoMapper公约

由于AutoMapper变平,它将 寻找:

匹配属性名称

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

方法开始W¯¯第i个字“获取”, 所以GetTotal()映射到总计

现有的任何类型的地图已经 配置

基本上,如果你删除了所有的 “点”和“获取”,AutoMapper将 比赛属性名称。现在, AutoMapper不匹配 类型,但由于其他一些原因不会失败。

0

我不能完全确定,但是你想什么作为你的最终结果,....

如果你比较两种不同类型的属性,你可以投影属性名称和相应的数值,两个字典。并用这些信息做一些排序/差异的财产价值。

 Guid newGuid = Guid.NewGuid(); 
     var classA = new ClassA{Id = newGuid}; 
     var classB = new ClassB{Id = newGuid}; 

     PropertyInfo[] classAProperties = classA.GetType().GetProperties(); 

     Dictionary<string, object> classAPropertyValue = classAProperties.ToDictionary(pName => pName.Name, 
                       pValue => 
                       pValue.GetValue(classA, null)); 

     PropertyInfo[] classBProperties = classB.GetType().GetProperties(); 
     Dictionary<string, object> 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]} 
1

仅使用.NET 2。0方法:

class Foo 
{ 
    public Guid Guid { get; } 
} 

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

如果你的类没有实现一个共同的接口,你必须实现GetFooSubset每种类型分别。

+0

.NET 2.0不支持lambda表达式,也不支持System.Linq添加的扩展方法。你的例子至少需要.NET 3.0。 – 2009-11-13 02:06:48

+1

@Karim:FindAll不是LINQ添加的扩展方法,而是列表“”类提供的常规方法,该类是自2.0版以来.NET框架的一部分。 Lambda表达式需要C#3.0编译器,但不一定需要.NET 3.0。 – dtb 2009-11-13 14:09:28

0

编辑方针基本上应该得到你想要的东西 - 但你可能会使用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<T1> t1s = new List<T1>() { 
      new T1(G1, "one"), 
      new T1(G2, "two"), 
      new T1(G3, "three") 
     }; 
     List<Guid> filter = new List<Guid>() { G2, G3}; 

     List<T1> filteredValues1 = t1s.FindAll(delegate(T1 item) 
     { 
      return filter.Contains(item.Guid); 
     }); 

     List<T1> filteredValues2 = t1s.FindAll(o1 => filter.Contains(o1.Guid)); 
    } 
} 
+0

我在那里有一些矫枉过正 - 编辑它。 – dice 2009-11-14 21:44:50

2

好的更好,如果你有机会到只修改原来的类来添加界面出现,马修就​​能辨出上。我在这里变得有点疯狂,并使用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<ClassTypeA> list1 = new List<ClassTypeA>(); 
      List<ClassTypeB> list2 = new List<ClassTypeB>(); 

      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<ICommonTypeMakeUpYourOwnName> common_list = 
         new List<ICommonTypeMakeUpYourOwnName>(); 

      //in english, give me everything in list 1 
      //and cast it to the interface 
      common_list.AddRange(
       list1.ConvertAll<ICommonTypeMakeUpYourOwnName>(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(); 
     } 

    } 
} 
+0

仅供参考...... OP说2.0;我假设2005 VS,所以没有3.0 VS 2008快捷键。 – Nathan 2009-11-12 22:08:37

+0

这工作很好。太糟糕了,我不能给出两个接受的答案。 – Chris 2009-11-12 22:25:39

相关问题