ベクトル間の距離行列を として表す 2D 配列を格納していDictionary<DistanceCell, double>
ます。私の実装にDistanceCell
は、比較されるベクトルを表す 2 つの文字列フィールドがあります。
class DistanceCell
{
public string Group1 { get; private set; }
public string Group2 { get; private set; }
public DistanceCell(string group1, string group2)
{
if (group1 == null)
{
throw new ArgumentNullException("group1");
}
if (group2 == null)
{
throw new ArgumentNullException("group2");
}
this.Group1 = group1;
this.Group2 = group2;
}
}
このクラスをキーとして使用しているので、 and をオーバーライドEquals()
しましたGetHashCode()
:
public override bool Equals(object obj)
{
// False if the object is null
if (obj == null)
{
return false;
}
// Try casting to a DistanceCell. If it fails, return false;
DistanceCell cell = obj as DistanceCell;
if (cell == null)
{
return false;
}
return (this.Group1 == cell.Group1 && this.Group2 == cell.Group2)
|| (this.Group1 == cell.Group2 && this.Group2 == cell.Group1);
}
public bool Equals(DistanceCell cell)
{
if (cell == null)
{
return false;
}
return (this.Group1 == cell.Group1 && this.Group2 == cell.Group2)
|| (this.Group1 == cell.Group2 && this.Group2 == cell.Group1);
}
public static bool operator ==(DistanceCell a, DistanceCell b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If either is null, return false.
// Cast a and b to objects to check for null to avoid calling this operator method
// and causing an infinite loop.
if ((object)a == null || (object)b == null)
{
return false;
}
return (a.Group1 == b.Group1 && a.Group2 == b.Group2)
|| (a.Group1 == b.Group2 && a.Group2 == b.Group1);
}
public static bool operator !=(DistanceCell a, DistanceCell b)
{
return !(a == b);
}
public override int GetHashCode()
{
int hash;
unchecked
{
hash = Group1.GetHashCode() * Group2.GetHashCode();
}
return hash;
}
ご覧のとおり、 の要件の 1 つはDistanceCell
、Group1
とGroup2
が交換可能であることです。したがって、2 つの文字列x
とはy
とDistanceCell("x", "y")
等しくなければなりませんDistanceCell("y", "x")
。これが、等しい必要がGetHashCode()
あるため、乗算を実装した理由です。DistanceCell("x", "y").GetHashCode()
DistanceCell("y", "x").GetHashCode()
私が抱えている問題は、おおよそ 90% の時間は正しく動作しますが、残りの時間はaKeyNotFoundException
または aをスローすることです。NullReferenceException
前者はディクショナリからキーを取得するときにスローされ、後者はforeach
ループを使用してディクショナリを反復処理し、null のキーを取得して呼び出しEquals()
を試みるときにスローされます。これは私の実装のエラーと関係があると思われますが、GetHashCode()
確信は持てません。また、アルゴリズムの性質上、キーをチェックしたときに辞書にキーが存在しないというケースは決してないはずです。アルゴリズムは、実行ごとに同じパスを取ります。
アップデート
問題が修正されたことを全員に更新したかっただけです。Equals() または GetHashCode() の実装とは何の関係もないことがわかりました。大規模なデバッグを行ったところ、KeyNotFoundException が発生した理由は、そもそもキーが辞書に存在しなかったためであることがわかりました。問題は、複数のスレッドを使用してディクショナリにキーを追加していたことでした。これによれば、c# ディクショナリ クラスはスレッドセーフではありません。したがって、Add() が失敗したため、キーがディクショナリに追加されなかったタイミングは完璧だったに違いありません。これは、foreach ループがときどき null キーを生成していたことも説明できると思います。Add()'
助けてくれてありがとう!完全に私のせいで終わってしまい申し訳ありません。