2010-05-12 12 views
2

La question provient de la comparaison des tables de base de données. Disons que nous mettons la ligne gauche dans l'instance Gauche et la droite dans l'instance Droite du même type. Et nous avons beaucoup de tables et types respectifs.Comparaison de diff de comparaison d'objet générique

Comment implémenter une routine plus ou moins générique résultant en une collection de diffs par ex.
propertyName, leftValue, rightValue pour chaque paire d'instances du même type. En dehors de l'algorithme de comparaison générique puisque leftValue et rightValue peuvent être n'importe quoi (paire de chaînes ou int ou DateTime ou Guid) n'est pas évident comment combiner tout cela dans une collection.

EDIT:

class OneOfManyTypesBasedOnTableRow 
{ 
    Guid uid, 
    int anotherId, 
    string text1, 
    string text2, 
    DateTime date1, 
    DateTime date2 
} 
class AnotherOfManyTypesBasedOnTableRow 
{ 
    Guid uid, 
    int anotherId, 
    string text3, 
    string text4, 
    DateTime date3, 
    DateTime date4 
} 

//For type 1 
OneOfManyTypesBasedOnTableRow Left = new Something().GetLeft() ; 
OneOfManyTypesBasedOnTableRow Right = new Something().GetRight() ; 
DiffCollection1 diff1 = comparer.GetDiffForOneOfManyTypesBasedOnTableRow (Left , Right) ; 

//For type 2 

AnotherOfManyTypesBasedOnTableRow Left = new SomethingElse().GetLeft() ; 
AnotherOfManyTypesBasedOnTableRow Right = new SomethingElse().GetRight() ; 
DiffCollection2 diff2 = comparer.GetDiffForAnotherOfManyTypesBasedOnTableRow (Left , Right) ; 

Mon problème est que je ne sais pas comment éviter la répétition de ce code assez similaire pour chaque type. Cela pourrait convenir à la population d'objets. Mais dans les méthodes diff je dois coder

if Left.Text1.Equals (Right.Text1) 

et ainsi de suite dans une méthode

if Left.Text3.Equals (Right.Text3) 

et ainsi de suite dans une autre méthode

+0

Pouvez-vous mettre en place un code de pseudo décrivant ceci. –

+0

Une chose que j'ai faite est de faire une méthode qui renvoie une liste des valeurs (dans l'ordre) qui sont "importantes". Ensuite, j'utilise cet objet liste (pas l'objet réel) pour comparer l'égalité et générer un hachage.Ceci est similaire à un processus légèrement plus automatisé comme mentionné dans la réponse de Mathew mais place la sélection "champ d'importation" entre les mains de l'objet (les attributs pourraient aussi être utilisés je suppose). Cela peut être fait très facilement à travers un certain nombre d'objets avec une interface et une aide statique ou une méthode d'extension - devrait être inférieure à ~ 8 lignes de code par classe. –

Répondre

3

Je ne sais pas si cela est exactement ce que vous voulez, mais cette méthode peut faire une comparaison superficielle sur deux objets correspondant aux propriétés et les comparer pour voir s'ils sont égaux.

private static bool DoObjectsMatch(object object1, object object2) 
{ 
    var props1 = object1.GetType() 
        .GetProperties() 
        .ToDictionary<PropertyInfo,string,object>(p => p.Name, p => p.GetValue(object1, null)); 
    var props2 = object2.GetType() 
        .GetProperties() 
        .ToDictionary<PropertyInfo,string,object>(p => p.Name, p => p.GetValue(object2, null)); 
    var query = from prop1 in props1 
       join prop2 in props2 on prop1.Key equals prop2.Key 
       select prop1.Value == null ? prop2.Value == null : prop1.Value.Equals(prop2.Value); 

    return query.Count(x => x) == Math.Max(props1.Count(), props2.Count()); 
} 

En utilisant cette méthode, vous pouvez comparer deux objets en fonction d'un nom de propriété correspondant. Par exemple:

class Thing 
{ 
    public int Id {get;set;} 
    public string Text{get;set;} 
} 

void Main() 
{ 
    var t1 = new Thing{ Id = 3, Text = "hi" }; 
    var t2 = new Thing{ Id = 3, Text = "hi" }; 
    var t3 = new Thing{ Id = 4, Text = "bye" }; 

    Console.WriteLine(DoObjectsMatch(t1,t2)); // True 
    Console.WriteLine(DoObjectsMatch(t2,t3)); // False 
} 
+0

Je préfère une approche "manuelle" légèrement plus verbeuse avec une sélection explicite de "valeurs importantes", mais une réponse générale sympa. –

1

J'ai créé une bibliothèque pour faire exactement cela et fournir des métadonnées supplémentaires. Malheureusement, il s'appuie sur MVC ModelMetadata et DataAnnotations pour fournir une "version lisible" de la diff pour les utilisateurs non techniques. Il utilisera donc votre DisplayName pour une propriété au lieu de son nom de propriété réel.

Mais il offre la possibilité d'obtenir une représentation par programme du diff pour vos propres utilisations au lieu d'utiliser les extensions "lisibles".

https://github.com/paultyng/ObjectDiff

objets donnés comme:

var before = new 
{ 
    Property1 = "", 
    MultilineText = "abc\ndef\nghi", 
    ChildObject = new { ChildProperty = 7 }, 
    List = new string[] { "a", "b" } 
}; 

var after = new 
{ 
    Property1 = (string)null, 
    MultilineText = "123\n456", 
    NotPreviouslyExisting = "abc", 
    ChildObject = new { ChildProperty = 6 }, 
    List = new string[] { "b", "c" } 
}; 

quelque chose de sortie lisible extensions de diff comme:

ChildObject - ChildProperty: '6', was '7' 
List - [2, added]: 'c', was not present 
List - [removed]: No value present, was 'a' 
MultilineText: 
----- 
123 
456 
----- 
was 
----- 
abc 
def 
ghi 
----- 
NotPreviouslyExisting: 'abc', was not present 

Mais la diff programmatique vous donnera des informations sur tous les biens et l'élément de liste et vous pourriez faire avec ce que vous voulez.

Je prévois de diviser l'exigence MVC à l'avenir, tout est ouvert, donc vous pouvez le pirater comme vous le ferez. C'est peut-être un bon endroit pour commencer si ce n'est pas exactement adapté à vos besoins.