2010-06-25 4 views
1

Dites que j'ai une classe spéciale, WrappedDataTable, et je veux associer chaque WrappedDataTable avec exactement un DataTable. En outre, je veux qu'il n'y ait pas plus d'un WrappedDataTable pour un DataTable donné.Est-ce totalement acceptable d'utiliser un objet mutable comme clé dans un dictionnaire?

Un collègue a suggéré que je pourrais mettre en cache mon WrappedDataTable et utiliser une méthode de fabrication pour accéder à une, comme ceci:

public static class DataTableWrapper 
{ 
    private Dictionary<DataTable, WrappedDataTable> _wrappedTables; 

    static DataTableWrapper() 
    { 
     _wrappedTables = new Dictionary<DataTable, WrappedDataTable>(); 
    } 

    public static WrappedDataTable Wrap(this DataTable table) 
    { 
     WrappedDataTable wrappedTable; 
     if (!_wrappedTables.TryGetValue(table, out wrappedTable)) 
      _wrappedTables[table] = wrappedTable = new WrappedDataTable(table); 

     return wrappedTable; 
    } 
} 

Cela m'a frappé comme très discutable d'abord, je suppose que parce que je suis devenu familier avec le idée que les clés dans un dictionnaire devraient être des types immuables. Mais peut-être que ce n'est pas nécessairement le cas? Un test rapide m'a révélé qu'un DataTable semble maintenir un code de hachage cohérent au cours de nombreuses modifications de son contenu; un Dictionary<DataTable, TValue> semble donc être en mesure de renvoyer une valeur correcte pour ContainsKey de manière cohérente. Ce que je me demande est si la version de base de object.GetHashCode par défaut retournera une valeur immuable pour chaque objet individuel, ou si ce que je vois avec DataTable est juste une illusion?

Si le premier est vrai - et object.GetHashCode fonctionne très bien - il semble que le conseil « utiliser uniquement les types immuables que les clés » vise que ses scénarios où:

  1. Vous voulez que l'égalité des objets à à propos de l'égalité des valeurs par opposition à l'égalité de référence, et/ou:
  2. Vous avez un type personnalisé avec sa propre implémentation GetHashCode basée sur les membres du type.

Y at-il des sages là-dedans pour me faire la lumière?


MISE À JOUR: Merci à Jon Skeet pour répondre à ma question. Dans d'autres nouvelles, j'ai creusé et pense que je suis venu avec un IEqualityComparer<T> que fournir une comparaison d'identité après tout! Check it out (désolé ceux qui haïssent VB.NET, je viens d'avoir un projet VB.NET afin que est ce que je l'ai écrit dans - traduction est trivial):

Imports System.Collections.Generic 
Imports System.Runtime.CompilerServices 

Public Class IdentityComparer(Of T As Class) 
    Implements IEqualityComparer(Of T) 

    Public Overloads Function Equals(ByVal x As T, ByVal y As T) As Boolean _ 
     Implements IEqualityComparer(Of T).Equals 

     Return Object.ReferenceEquals(x, y) 
    End Function 

    Public Overloads Function GetHashCode(ByVal obj As T) As Integer _ 
     Implements IEqualityComparer(Of T).GetHashCode 

     Return RuntimeHelpers.GetHashCode(obj) 
    End Function 
End Class 

Jetez un oeil à cet exemple programme:

Dim comparer As IEqualityComparer(Of String) = New IdentityComparer(Of String) 

Dim x As New String("Hello there") 
Dim y As New String("Hello there") 

Console.WriteLine(comparer.Equals(x, y)) 
Console.WriteLine(comparer.GetHashCode(x)) 
Console.WriteLine(comparer.GetHashCode(y)) 

sortie:

 
False 
37121646 
45592480 

Répondre

2

Il ne doit pas retourner une valeur unique. Il doit juste en retourner un qui ne change pas - et c'est ce que fait object.GetHashCode.

Tant que DataTable ne remplace pas Equals ou GetHashCode, vous avez essentiellement l'identité de l'objet comme égalité - ce qui signifie que cela n'a pas d'importance si l'objet est muté.

Personnellement, je voudrais voir une mise en œuvre de IEqualityComparer<T> qui fournit l'égalité d'identité pour tout type, mais nous ne pouvons pas mettre en œuvre que nous - il n'y a aucun moyen de savoir ce que GetHashCode aurait sont revenus si elle n'avait pas été annulé. (Java a cette capacité dans ses bibliothèques standard, mais .NET ne Grr..)

EDIT: Woot - avec object.ReferenceEquals et RuntimeHelpers.GetHashCode(), nous pouvons facilement mettre en œuvre un IdentityEqualityComparer<T>. Yay!

+0

@Jon: Comme un GetHashCodeBase? J'avoue que je n'ai jamais fait de Java (nodatime était ma première incursion et j'ai passé tout le temps à regarder le code plutôt qu'à contribuer) –

+0

@Jeff: Une sorte de méthode statique quelque part, en gros. En Java c'est 'System.identityHashCode' –

+0

@Jon: Ah, cela semble utile. Serait également utile d'être en mesure d'obtenir les implémentations originales de ToString et Equals à d'autres fins. –

0

Je pense que vous comprenez bien les choses. Pour qu'un objet soit stocké dans un dictionnaire, toutes les caractéristiques qui affecteraient sa valeur de hachage ou les tests d'égalité avec d'autres objets doivent être immuables. Les caractéristiques qui n'affecteraient pas ces choses ne sont pas nécessairement immuables.

Questions connexes