2009-11-12 20 views
5

Todo esto está en C#, usando .NET 2.0.Cómo comparar dos objetos claramente diferentes con propiedades similares

Tengo dos listas de objetos. No son objetos relacionados, pero sí tienen ciertas cosas en común que se pueden comparar como un identificador único basado en Guid ( ). Estas dos listas necesitan para ser filtradas por otra lista que solo contenga Guid's que puede o no coincidir con las ID contenidas en las primeras dos listas.

He pensado en la idea de convertir cada lista de objetos en solo 'objeto' y ordenar por eso, pero no estoy seguro de que pueda acceder a la propiedad de ID una vez que se lance, y yo ' m pensando que el método para ordenar las dos listas debe ser algo tonto al saber cuál es la lista que se va a ordenar.

¿Cuál sería la mejor manera de traer cada lista de objetos para que pueda clasificarse en la lista con solo los ID?

+0

¿Clasifica o filtra? Ordenando por qué? – dtb

+0

Filtrado en realidad. object.GuidId == list.GuidId return object. – Chris

Respuesta

15

Debe hacer que cada uno de sus objetos implemente una interfaz común. A continuación, cree un IComparer < T> para esa interfaz y úselo en su género.

+3

Si puede implementar una interfaz común (porque no posee uno o ambos objetos), querrá crear clases de adaptadores que implementen la interfaz común. Entonces estás dorado. – plinth

+0

En otras palabras, esencialmente está convirtiendo cada objeto en un tipo de clase (interfaz) que contiene los elementos comunes de ambos, y luego compara los objetos resultantes (del mismo tipo). El uso de una interfaz evita las operaciones explícitas de lanzamiento. –

+0

Creo que sería interesante tener algo como Jimmy's AutoMapper para registrar una clase como IComparer para tipos de objetos relacionados. ¿Pensamientos? –

0

No estoy seguro de entender por completo lo que desea, pero puede usar linq para seleccionar los elementos coincidentes de las listas y ordenarlos. Aquí hay un ejemplo simple en el que los valores de una lista se filtran en otra y se ordenan.

 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

No he tenido la oportunidad de utilizar AutoMapper todavía, pero de lo que usted describe que deseen check it out. Desde el puesto de Jimmy Bogard:

convenciones AutoMapper

Desde AutoMapper aplana, lo hará mirada para:

nombres de propiedades Matching

nombres de propiedades anidadas (product.name mapas a ProductName, asumiendo una convención de nomenclatura PascalCase de )

Métodos que inician w on la palabra “GET”, por lo getTotal() Mapas a Total

Cualquier tipo de mapa ya existente configurado

Básicamente, si ha quitado todas las “puntos” y “entiende”, AutoMapper se partido nombres de propiedad. En este momento, AutoMapper no falla en los tipos no coincidentes, pero por otros motivos.

0

no estoy totalmente seguro de lo que quieres como sus resultados finales, sin embargo ....

Si se comparan las propiedades de dos tipos diferentes se podría proyectar los nombres de las propiedades y los valores correspondientes en dos diccionarios . Y con esa información haga algún tipo de clasificación/diferencia de los valores de la propiedad.

 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

Usando solamente .NET 2.0 métodos:

class Foo 
{ 
    public Guid Guid { get; } 
} 

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

Si sus clases no implementan una interfaz común, que tendrán que aplicar GetFooSubset para cada tipo individual.

+0

.NET 2.0 no admite expresiones lambda ni tiene los métodos de extensión agregados por System.Linq. Su ejemplo requiere al menos .NET 3.0. –

+1

@Karim: FindAll no es un método de extensión agregado por LINQ, sino un método habitual proporcionado por la clase 'List ' que forma parte del framework .NET desde la versión 2.0. Las expresiones Lambda requieren un compilador C# 3.0, pero no necesariamente .NET 3.0. – dtb

0

thist en esencia lo que debe conseguir lo que quieres - pero puede ser mejor de utilizar 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

Tuve algunos excesos allí - editándolo. – dice

2

bien, si tiene acceso a modificar sólo las clases originales para agregar la interfaz de allí, Mateo tenía el clavo en. Me volví un poco loco aquí y definí una solución completa usando 2.0 delegados anónimos. (Creo que soy muy adicto a 3.0 Lambda; de lo contrario, probablemente hubiera escrito esto en foreach loops si todavía estuviera usando 2005).

Básicamente, cree una interfaz con las propiedades comunes. Haz que yoru dos clases implementen la interfaz. Cree una lista común como la interfaz, eche y elimine los valores en la nueva lista; eliminar cualquier elemento no coincidente.

//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

FYI ... OP dijo 2.0; Asumo 2005 VS, por lo que no hay atajos 3.0 VS 2008. – Nathan

+0

Esto funciona bastante bien. Lástima que no puedo dar dos respuestas aceptadas. – Chris

Cuestiones relacionadas