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 似乎保持了一致的哈希码;因此, aDictionary<DataTable, TValue>似乎能够ContainsKey一致地返回正确的值。

我想知道的是object.GetHashCode,默认情况下的基本版本是否会为每个单独的对象返回一个不变的值,或者我所看到DataTable的只是一种错觉?

如果前者是真的——并且object.GetHashCode工作得很好——那么“只使用不可变类型作为键”的建议似乎真的只适用于以下场景:

  1. 您希望对象的平等是关于价值平等而不是引用平等,和/或:
  2. 您有一个自定义类型,它有自己的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
4

2 回答 2

2

它不必返回唯一值。它只需要返回一个不变的 - 就是object.GetHashCode这样。

只要DataTable不覆盖Equalsor GetHashCode,您基本上就可以将对象身份视为相等 - 这意味着对象是否发生变异并不重要。

就我个人而言,我希望看到一个为任何IEqualityComparer<T>类型提供身份平等的实现,但我们自己无法实现 -如果没有被覆盖,无法找出会返回的内容。(Java 在其标准库中具有此功能,但 .NET 没有。Grr。)GetHashCode

编辑:Woot - 使用object.ReferenceEqualsand RuntimeHelpers.GetHashCode(),我们可以轻松实现IdentityEqualityComparer<T>. 耶!

于 2010-06-25T13:03:10.847 回答
0

I think you understand things fine. For an object to be stored in a dictionary, any characteristics which would affect its hash value or tests for equality with other objects must be immutable. Characteristics which would not affect those things need not be immutable.

于 2010-06-29T20:21:31.890 回答