0

このクラスを見てください:

public class MemorialPoint:IMemorialPoint,IEqualityComparer<MemorialPoint>
{
    private string _PointName;
    private IPoint _PointLocation;
    private MemorialPointType _PointType;

    private DateTime _PointStartTime;
    private DateTime _PointFinishTime;

    private string _NeighborName;

    private double _Rms;
    private double _PointPdop;
    private double _PointHdop;
    private double _PointVdop;

    // getters and setters omitted

    public bool Equals(MemorialPoint x, MemorialPoint y)
    {
        if (x.PointName == y.PointName)
            return true;
        else if (x.PointName == y.PointName && x.PointLocation.X == y.PointLocation.X && x.PointLocation.Y == y.PointLocation.Y)
            return true;
        else
            return false;
    }

    public int GetHashCode(MemorialPoint obj)
    {
        return (obj.PointLocation.X.ToString() + obj.PointLocation.Y.ToString() + obj.PointName).GetHashCode();
    }
}

また、Vector クラスもあります。これは、2 つのポイントとその他の属性だけです。ベクターに同じポイントを持ちたくないので、次の方法を思いつきました。

public void RecalculateVector(IMemorialPoint fromPoint, IMemorialPoint toPoint, int partIndex)
        {
            if (fromPoint.Equals(toPoint))
                throw new ArgumentException(Messages.VectorWithEqualPoints);

            this.FromPoint = FromPoint;
            this.ToPoint = ToPoint;
            this.PartIndex = partIndex;

            // the constructDifference method has a weird way of working:
            // difference of Point1 and Point 2, so point2 > point1 is the direction
            IVector3D vector = new Vector3DClass();
            vector.ConstructDifference(toPoint.PointLocation, fromPoint.PointLocation);

            this.Azimuth = MathUtilities.RadiansToDegrees(vector.Azimuth);

            IPointCollection pointCollection = new PolylineClass();
            pointCollection.AddPoint(fromPoint.PointLocation, ref _missing, ref _missing);
            pointCollection.AddPoint(toPoint.PointLocation, ref _missing, ref _missing);

            this._ResultingPolyline = pointCollection as IPolyline;
        }

そして、この単体テストでは、例外が発生するはずです:

    [TestMethod]
    [ExpectedException(typeof(ArgumentException), Messages.VectorWithEqualPoints)]
    public void TestMemoriaVector_EqualPoints()
    {
        IPoint p1 = PointPolygonBuilder.BuildPoint(0, 0);
        IPoint p2 = PointPolygonBuilder.BuildPoint(0, 0);

        IMemorialPoint mPoint1 = new MemorialPoint("teste1", p1);
        IMemorialPoint mPoint2 = new MemorialPoint("teste1", p2);

        Console.WriteLine(mPoint1.GetHashCode().ToString());
        Console.WriteLine(mPoint2.GetHashCode().ToString());

        vector = new MemorialVector(mPoint1, mPoint1, 0);
    }

コードのように同じポイント、つまり mPoint1 を使用すると、例外がスローされます。mPoint2 を使用すると、名前と座標が同じであっても、例外はスローされません。ハッシュコードを調べたところ、実際には異なっていました。GetHashCode で作成したコードに基づいて、これら 2 つのポイントは同じハッシュコードを持つと考えました。

なぜこれが私が思ったように機能しないのか、誰かが私に説明できますか? 私はこれをうまく説明したかどうか確信が持てませんが..私は助けに感謝します:D

ジョージ

4

4 に答える 4

4

IEqualityComparer<T>比較しようとしている型内で実装しています-これは非常に奇妙です。ほとんどの場合、代わりに実装IEquatable<T>してオーバーライドする必要がありますEquals(object)。それは間違いなくあなたの単体テストを機能させるでしょう。

IEquatable<T>との違いは、前者は「同じ型の別のインスタンスと自分IEqualityComparer<T>を比較できる」というクラスによって実装されていることです。(同じ型である必要はありません、通常は同じです。) これは、自然な比較がある場合に適しています。たとえば、 によって選択された比較が序数の等しさである場合、値のシーケンスがまったく同じである必要があります。stringchar

現在IEqualityComparer<T>は異なります。型の任意の 2 つのインスタンスを比較できます。特定のタイプに対してこれには複数の異なる実装が存在する可能性があるため、特定の比較が「自然なもの」であるかどうかは問題ではありません-それはあなたの仕事に適したものでなければなりません. したがって、たとえば、Shapeクラスと、色、面積などで形状を比較するさまざまな等値比較子を使用できます。

于 2010-06-24T15:55:39.440 に答える
1

また、現在.NET Frameworkの 要件を満たしていないため、「同等性」の概念を再考する必要があります。

可能であれば、メモリアルポイントオブジェクトのリポジトリ(名前でキー設定されている可能性があります)を使用して再設計することをお勧めします。これにより、単純な参照の同等性を使用できます。

于 2010-06-24T16:09:17.060 に答える
1

Object.Equals同様 にオーバーライドする必要があります。

これを実装に追加します。

// In MemorialPoint:
public override bool Equals(object obj)
{
    if (obj == null || GetType() != obj.GetType()) 
         return false;

    MemorialPoint y = obj as MemorialPoint;

    if (this.PointName == y.PointName)
        return true;
    else if (this.PointName == y.PointName && this.PointLocation.X == y.PointLocation.X && this.PointLocation.Y == y.PointLocation.Y)
        return true;
    else
        return false;
}

次に、最初の実装を使用するように他の実装を作り直し、さらに適切な null チェックを追加します。

public bool Equals(MemorialPoint x, MemorialPoint y)
{
    if (x == null)
        return (y == null);
    return x.Equals(y);
}
于 2010-06-24T15:51:33.357 に答える
1

これに arcobjects タグを付けたので、 IRelationalOperator.Equals について言及したいと思いました。この方法がジオメトリの空間参照のクラスター許容値を尊重するかどうかを確認するためにテストしたことはありません。これはISpatialReferenceTolerance.XYToleranceを使用して調整できます。

于 2010-06-25T14:02:33.557 に答える