2010-02-11 3 views
12

Étant donné deux instances d'une classe, est-il une bonne et fiable pratique de les comparer en les sérialisant d'abord, puis en comparant les tableaux d'octets (ou éventuellement les hachages de tableaux). Ces objets peuvent avoir des propriétés hiérarchiques complexes, mais la sérialisation doit aller aussi loin que nécessaire. Par comparaison, je veux dire le processus de s'assurer que toutes les propriétés des types primitifs ont des valeurs égales, les propriétés des types complexes ont des propriétés égales des types primitifs, etc. Quant aux propriétés de collection, elles doivent être égales entre elles: égales éléments, les mêmes positions:Est-il fiable de comparer deux instances d'une classe en comparant leurs tableaux d'octets sérialisés?

{'a','b','c'} != {'a','c','b'} 



{new Customer{Id=2, Name="abc"}, new Customer {Id=3, Name="def"}} 
    != 
{new Customer{Id=3, Name="def"}, new Customer {Id=2, Name="abc"}} 

mais

{new Customer{Id=2, Name="abc"}, new Customer {Id=3, Name="def"}} 
    == 
{new Customer{Id=2, Name="abc"}, new Customer {Id=3, Name="def"}} 

Et par sérialisation je veux dire formatter binaire standard .NET.

Merci.

+1

Dans quel but voudriez-vous faire ce genre de comparaison? Cela pourrait aider à fournir une réponse plus détaillée. – BlueMonkMN

+0

Je connais actuellement deux façons de comparer des objets (ceux qui n'implémentent pas IComparable ou IEquattable), avec PropertyInfo et PropertyDescriptor. Ce pourrait être simplement un troisième outil dans ma boîte à outils. Mais je suis intéressé par l'applicabilité générale et la fiabilité de cette méthode. Peut-il donner de mauvais résultats? – Valentin

Répondre

5

Vous demandez une garantie que la représentation sérialisée correspondra. Ça va être terriblement difficile à trouver, BinaryFormatter est une classe compliquée. Les structures particulièrement sérialisées qui ont un rembourrage d'alignement pourraient être un problème potentiel.

Ce qui est beaucoup plus simple est de fournir un exemple où il ne correspondra pas. System.Decimal a différents modèles d'octets pour des valeurs telles que 0.01M et 0.010M. Son opérateur ==() dira qu'ils sont égaux, son octet sérialisé [] ne le sera pas.

2

Vous devriez définir ce que l'égalité signifie ici encore plus précisément.

Si l'une des propriétés est une collection, il peut y avoir des différences dans l'ordre (suite à des séquences d'ajout/suppression particulières) qui peuvent ou non être significatives pour vous. Pensez à un dictionnaire où les mêmes éléments ont été ajoutés dans un ordre différent. Une collision peut entraîner un flux binaire différent.

2

Il est fiable si:

  1. Chaque classe unique dans le graphique est marqué [Serializable]. Ce n'est pas aussi simple que cela puisse paraître; Si vous comparez des objets totalement arbitraires, il y a de fortes chances qu'il y ait quelque chose de non sérialisable là-dedans qui vous échappe.

  2. Vous voulez savoir si les deux instances sont exactement la même chose. Gardez à l'esprit que BinaryFormatter est fondamentalement plongée dans l'état interne de ces objets, donc même s'ils semblent être les mêmes en vertu des propriétés publiques, ils pourraient ne pas l'être. Si vous savez pertinemment que le graphe est créé exactement de la même manière dans chaque cas, peut-être que vous ne vous en souciez pas; mais sinon, il peut y avoir un certain nombre de différences cachées entre les graphiques.

    Ce point est aussi une ride plus sérieuse qu'on ne pourrait le penser. Et si vous décidez d'échanger la classe avec une interface? Vous pouvez avoir deux interfaces qui, à votre connaissance, sont exactement les mêmes; ils accomplissent la même tâche et fournissent les mêmes données. Mais ils pourraient être des implémentations totalement différentes. Ce qui est bien sur IEquatable, c'est qu'il est indépendant du type de béton.

donc ça travail, pour un grand nombre de cas, mais je ne serais probablement pas le considérer comme une bonne pratique, du moins pas sans connaître tous les détails sur le contexte spécifique qu'il est utilisé dans À tout le moins, je ne compterais pas sur cela comme une méthode de comparaison générique pour deux deux instances; Il ne doit être utilisé que dans des cas spécifiques où vous connaissez les détails d'implémentation des classes impliquées.

Bien sûr, certains pourraient dire que l'écriture de tout code qui dépend des détails d'implémentation d'une classe est toujours une mauvaise pratique.Mon point de vue sur ce sujet est plus modéré, mais c'est quelque chose à considérer - s'appuyer sur les détails d'implémentation d'une classe peut conduire à un code difficile à maintenir plus tard.

+0

En ce qui concerne le point 1), un type non sérialisable dans le graphique lèvera une exception. –

Questions connexes