【发布时间】:2011-03-08 06:49:58
【问题描述】:
假设我有一些特殊的课程WrappedDataTable,我想将每个WrappedDataTable 与一个DataTable 关联起来。此外,对于任何给定的DataTable,我希望存在的WrappedDataTable 不超过一个。
一位同事建议我可以缓存我的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 是否只是一种错觉?
如果前者是真的——而且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))
输出:
错误的 37121646 45592480【问题讨论】:
标签: .net dictionary key immutability gethashcode