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ù:
- Vous voulez que l'égalité des objets à à propos de l'égalité des valeurs par opposition à l'égalité de référence, et/ou:
- 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
@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) –
@Jeff: Une sorte de méthode statique quelque part, en gros. En Java c'est 'System.identityHashCode' –
@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. –