9
votes

Comparer les propriétés automatiquement

Je veux obtenir les noms de toutes les propriétés qui ont changé pour faire correspondre des objets. J'ai ces classes (simplifiées): xxx p> maintenant je veux maintenant obtenir le Objets où les valeurs de la propriété diffèrent: xxx

à la fin je souhaite avoir une liste de différence s comme celui-ci: < Pré> xxx

Le modifiéProperty doit contenir le nom des propriétés modifiées.


5 commentaires

Faire cela pour les listes est une douleur réelle (supposant que vous devez manipuler ajouter / supprimer / re-commande / etc.); Cependant, sur une base d'objet, veuillez consulter: Stackoverflow.com/questions/3060382/... - qui fait exactement ce


@Marcgravell: Je l'ai essayé et cela renvoie les attributs qui sont des listes comme Delta. Merci quand même.


Vous souciez-vous des propriétés qui ne sont pas dans les deux objets, c'est-à-dire La matriculation est-elle considérée comme une modification lorsque vous comparez une personne à un étudiant?


Je correspond aux personnes avec la propriété nom , puis la comparez si une correspondance est trouvée. Donc, seuls les objets du même type peuvent être comparés.


Depuis que les sujets sont une liste, si 1 professeur dispose de 2 éléments de sujet de la liste et d'autres professeurs a par exemple seulement 1 ou 3, cet élément supplémentaire ou moins sujet aurait la différence?


5 Réponses :


0
votes

Je le fais en utilisant ceci:

    //This structure represents the comparison of one member of an object to the corresponding member of another object.
    public struct MemberComparison
    {
        public static PropertyInfo NullProperty = null; //used for ROOT properties - i dont know their name only that they are changed

        public readonly MemberInfo Member; //Which member this Comparison compares
        public readonly object Value1, Value2;//The values of each object's respective member
        public MemberComparison(PropertyInfo member, object value1, object value2)
        {
            Member = member;
            Value1 = value1;
            Value2 = value2;
        }

        public override string ToString()
        { 
            return Member.name+ ": " + Value1.ToString() + (Value1.Equals(Value2) ? " == " : " != ") + Value2.ToString();
        }
    }

    //This method can be used to get a list of MemberComparison values that represent the fields and/or properties that differ between the two objects.
    public static List<MemberComparison> ReflectiveCompare<T>(T x, T y)
    {
        List<MemberComparison> list = new List<MemberComparison>();//The list to be returned

        if (x.GetType().IsArray)
        {
            Array xArray = x as Array;
            Array yArray = y as Array;
            if (xArray.Length != yArray.Length)
                list.Add(new MemberComparison(MemberComparison.NullProperty, "array", "array"));
            else
            {
                for (int i = 0; i < xArray.Length; i++)
                {
                    var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
                    if (compare.Count > 0)
                        list.AddRange(compare);
                }
            }
        }
        else
        {
            foreach (PropertyInfo m in x.GetType().GetProperties())
                //Only look at fields and properties.
                //This could be changed to include methods, but you'd have to get values to pass to the methods you want to compare
                if (!m.PropertyType.IsArray && (m.PropertyType == typeof(String) || m.PropertyType == typeof(double) || m.PropertyType == typeof(int) || m.PropertyType == typeof(uint) || m.PropertyType == typeof(float)))
                {
                    var xValue = m.GetValue(x, null);
                    var yValue = m.GetValue(y, null);
                    if (!object.Equals(yValue, xValue))//Add a new comparison to the list if the value of the member defined on 'x' isn't equal to the value of the member defined on 'y'.
                        list.Add(new MemberComparison(m, yValue, xValue));
                }
                else if (m.PropertyType.IsArray)
                {
                    Array xArray = m.GetValue(x, null) as Array;
                    Array yArray = m.GetValue(y, null) as Array;
                    if (xArray.Length != yArray.Length)
                        list.Add(new MemberComparison(m, "array", "array"));
                    else
                    {
                        for (int i = 0; i < xArray.Length; i++)
                        {
                            var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
                            if (compare.Count > 0)
                                list.AddRange(compare);
                        }
                    }
                }
                else if (m.PropertyType.IsClass)
                {
                    var xValue = m.GetValue(x, null);
                    var yValue = m.GetValue(y, null);
                    if ((xValue == null || yValue == null) && !(yValue == null && xValue == null))
                        list.Add(new MemberComparison(m, xValue, yValue));
                    else if (!(xValue == null || yValue == null))
                    {
                        var compare = ReflectiveCompare(m.GetValue(x, null), m.GetValue(y, null));
                        if (compare.Count > 0)
                            list.AddRange(compare);
                    }


                }
        }
        return list;
    }


1 commentaires

Je reçois un Nombre de paramètres Mismatch Exception lorsque j'utilise cela.



3
votes

Nous commençons par 2 méthodes simples: xxx pré>

areequal compare simplement les versions sérialisées de deux objets à l'aide de JSON.NET, cela le permet de traiter les types de référence et les types de valeur différemment. P >

GetDifefence vérifie les propriétés sur les objets transmis et les compare individuellement. P>

Pour obtenir une liste de différences: p>

var oldPersonList = new List<Person> { 
    new Person { Name = "Bill" }, 
    new Person { Name = "Bob" }
};

var newPersonList = new List<Person> {
    new Person { Name = "Bill" },
    new Person { Name = "Bobby" }
};

var diffList = oldPersonList.Zip(newPersonList, GetDifference)
    .Where(d => d.ChangedProperties.Any())
    .ToList();


0 commentaires

0
votes

Ici, vous avez un code qui fait ce que vous voulez avec réflexion . xxx


0 commentaires

6
votes

J'ai passé tout en œuvre en essayant d'écrire une solution de réflexion plus rapide à l'aide de délégués dactylographiés. Mais éventuellement, j'ai abandonné et éventé à Marc Gravell's bibliothèque membre rapide pour atteindre des performances plus élevées qu'avec la réflexion normale.

Code: strong> P>

PropertyComparer pc = new PropertyComparer();
var diffs = PropertyComparer.GetDifferences(pc, oldPersonList, newPersonList).ToList();


0 commentaires

2
votes

Tout le monde essaie toujours de se fier et d'écrire ces moyens trop génériques d'extraction de données. Il y a un coût à cela.

Pourquoi ne pas être vieille école simple. P>

avoir une fonction de fonction membre getDifferrences. P>

 virtual List<String> GetDifferences(Person otherPerson){
   var diffs = new List<string>();
   if(this.X != otherPerson.X) diffs.add("X");
   ....
 }


2 commentaires

Cela fonctionnera. Mais cela ne prendra pas 10 minutes. Mes cours sont beaucoup plus complexes que l'exemple que j'ai donné. Il faudra au moins une journée, avec des lignes de code HunDrets et des erreurs éventuelles dans ce code.


Assurez-vous de peser la perf. Si un faible nombre de comparaisons, la route de réflexion est bien. Si vous courez cela plus de centaines de milliers +, je serais plus méfiant.