2010-06-25 3 views
1

Скажем, у меня есть специальный класс, WrappedDataTable, и я хочу связать каждый WrappedDataTable ровно с одним DataTable. Кроме того, я хочу, чтобы существовало не более одного WrappedDataTable для любого заданного DataTable.Можно ли использовать изменяемый объект в качестве ключа в словаре?

Коллега предложил я мог кэшировать мой WrappedDataTable и использовать фабричный метод для доступа к одному, как это:

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; 
    } 
} 

Это поразило меня, как очень сомнительно сначала, я думаю, потому что я стал знаком с идея, что ключи в словаре должны быть неизменяемыми типами. Но, возможно, это не обязательно так? Быстрый тест показал мне, что DataTable, по-видимому, поддерживает согласованный хеш-код в ходе многочисленных модификаций его содержимого; a Dictionary<DataTable, TValue> похоже, что нужно сделать правильный вывод для ContainsKey.

Что мне интересно, если базовая версия object.GetHashCode по умолчанию вернет неизменное значение для каждого отдельного объекта, или если то, что я вижу с DataTable, просто иллюзия?

Если верно первое - и object.GetHashCode прекрасно работает - кажется, «используют только неизменные типы в качестве ключей» совет действительно относится только к сценариям, где:

  1. Вы хотите равенство объектов быть о равенстве значений в противоположность эталонному равенству и/или:
  2. У вас есть собственный тип с собственной реализацией GetHashCode, основанный на членах типа.

Любые мудрецы там могут пролить свет на это для меня?


UPDATE: Благодаря Jon тарелочкам для ответа на мой вопрос. В других новостях, я сделал некоторые копания и думаю, что я придумал IEqualityComparer<T>, что делает обеспечить сравнение идентичности в конце концов! Проверьте это (извините VB.NET ненавистники, я просто был проект VB.NET так это то, что я написал в - перевод тривиальна):

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 

Взгляните на этот пример программы:

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)) 

Выход:

 
False 
37121646 
45592480 

ответ

2

Он не должен возвращать уникальное значение. Он просто должен вернуть неизменный - и вот что делает object.GetHashCode.

Пока DataTable не переопределяет Equals или GetHashCode, вы в основном получили идентификатор объекта как равенство - это означает, что не имеет значения, был ли объект мутирован.

Лично я хотел бы видеть реализацию IEqualityComparer<T>, которая обеспечивает тождественное равенство любого типа, но мы не можем реализовать, что мы сами - нет никакого способа узнать, что GetHashCode бы вернулись если он не было отменено. (Java имеет эту возможность в своих стандартных библиотеках, но .NET не Grr.).

EDIT: Woot - с object.ReferenceEquals и RuntimeHelpers.GetHashCode(), можно легко реализовать IdentityEqualityComparer<T>. Ура!

+0

@Jon: Как GetHashCodeBase? Я признаю, что я никогда не делал Java (nodatime был моим первым набегом, и я все время смотрел на код, а не на то, чтобы внести свой вклад) –

+0

@Jeff: Какой-то статический метод где-то, в основном. В Java это 'System.identityHashCode' –

+0

@Jon: Ах, это звучит полезно. Было бы также полезно иметь возможность получить исходные реализации «ToString» и «Equals» для других целей. –

0

Я думаю, что вы прекрасно понимаете вещи. Чтобы объект хранился в словаре, любые характеристики, которые влияют на его хэш-значение или тесты на равенство с другими объектами, должны быть неизменными. Характеристики, которые не влияют на эти вещи, не обязательно должны быть неизменными.

 Смежные вопросы

  • Нет связанных вопросов^_^