假设我有一些特殊课程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
似乎在对其内容进行多次修改的过程中保持一致的哈希码;因此,Dictionary<DataTable, TValue>
似乎能够始终为ContainsKey
返回正确的值。
我想知道的是,默认情况下object.GetHashCode
的基本版本是否会为每个单独的对象返回一个不变的值,或者我在DataTable
看到的只是一种幻觉?< / p>
如果前者是真的 - 并且object.GetHashCode
工作正常 - 似乎“仅使用不可变类型作为键”建议实际上仅适用于以下情况:
GetHashCode
实现。那里的任何一位圣贤都在为我揭示这一点?
更新:感谢Jon Skeet回答我的问题。在其他新闻中,我做了一些挖掘,并认为我想出了一个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
答案 0 :(得分:2)
它不必返回唯一值。它必须返回一个不变的 - 这就是object.GetHashCode
所做的。
只要DataTable
不覆盖Equals
或GetHashCode
,您基本上就会将对象标识视为相等 - 这意味着对象是否发生变异无关紧要。
就我个人而言,我希望看到 IEqualityComparer<T>
的实现为任何类型提供身份相同,但我们无法自己实现 - 无法找到如果没有被覆盖,那么GetHashCode
将返回的内容。 (Java在其标准库中具有此功能,但.NET没有.Grr。)
编辑:Woot - 使用object.ReferenceEquals
和RuntimeHelpers.GetHashCode()
,我们可以轻松实现IdentityEqualityComparer<T>
。耶!
答案 1 :(得分:0)
我觉得你理解得很好。对于要存储在字典中的对象,任何会影响其散列值的特性或与其他对象相等的测试都必须是不可变的。不会影响这些事情的特征不一定是不可改变的。