1

特別なクラスがあり、それぞれを1つだけWrappedDataTableに関連付けたいとします。さらに、特定のに対して存在するのは1つだけである必要があります。WrappedDataTableDataTableWrappedDataTableDataTable

同僚は、次のように、自分をキャッシュ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タイプのメンバーに基づく独自の実装を持つカスタムタイプがあります。

私のためにこれに光を当てる気になっている賢人はいますか?


更新:私の質問に答えてくれたJonSkeetに感謝します。他のニュースでは、私はいくつかの掘り下げを行い、結局のところアイデンティティ比較を提供するものを思いついたと思い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オーバーライドしない限り、基本的にオブジェクトIDは同等であると見なされます。つまり、オブジェクトが変更されているかどうかは関係ありません。EqualsGetHashCode

個人的には、どのIEqualityComparer<T>タイプにもIDの同等性を提供する実装を見たいのですが、それを自分で実装することはできません。オーバーライドされなかった場合に何が返されるかを知る方法はありません。(Javaには標準ライブラリにこの機能がありますが、.NETにはありません。Grr。)GetHashCode

編集:Woot-とを使用するobject.ReferenceEqualsRuntimeHelpers.GetHashCode()、を簡単に実装できますIdentityEqualityComparer<T>。わーい!

于 2010-06-25T13:03:10.847 に答える
0

あなたは物事をうまく理解していると思います。オブジェクトをディクショナリに格納するには、そのハッシュ値に影響を与える特性や、他のオブジェクトとの同等性のテストが不変である必要があります。それらに影響を与えない特性は不変である必要はありません。

于 2010-06-29T20:21:31.890 に答える