Вопрос

Посмотрите на этот класс:

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();
    }
}

У меня также есть векторный класс, который является просто двумя точками и некоторые другие атрибуты. Я не хочу иметь равные очки в моем векторе, поэтому я придумал этот метод:

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, я записал эти две точки, будет иметь один и тот же Hashcode.

Может ли кто-нибудь объяснить мне, почему это не работает, как я зарубей это? Я не уверен, что объяснил это хорошо, но .. Я ценю помощь: D

Джордж

Это было полезно?

Решение

Вы реализуете IEqualityComparer<T> В том числе он пытается сравнить - что очень странно. Вы должны почти наверняка просто реализовать IEquatable<T> и переопределение Equals(object) вместо. Это определенно сделает вашу единицу тестируемой работой.

Разница между IEquatable<T> и IEqualityComparer<T> это то, что первое реализуется классом, чтобы сказать: «Я могу сравнить сам с другим экземпляром того же типа ». (Это не имеют быть тем же типом, но обычно это.) Это уместно, если есть естественное сравнение - например, сравнение, выбранное string является порядковым равенством - это должно быть точно та же последовательность char ценности.

Теперь IEqualityComparer<T> отличается - это может сравнить любые два экземпляра типа. Там могут быть несколько различных реализаций этого для данного типа, поэтому не имеет значения, является ли особая сравнение «естественным» - просто нужно быть правильным для вашей работы. Так например, вы могли бы иметь Shape Класс, и другое равенство сравнивает сравнивать фигуры по цвету, области или что-то в этом роде.

Другие советы

Вам нужно переопределить 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;
}

Затем я переделал вашу другую реализацию для использования первого, плюс добавить соответствующие нулевые проверки.

public bool Equals(MemorialPoint x, MemorialPoint y)
{
    if (x == null)
        return (y == null);
    return x.Equals(y);
}

Вам также нужно переосмыслить вашу концепцию «равенства», поскольку она в настоящее время не встречается .NET рамки требования.

Если вообще возможно, я рекомендую повторную конструкцию с репозиторием мемориальных точек объектов (возможно, ключом по имени), так что можно использовать простое ссылочное равенство.

Вы положили тег ArcObjects на это, поэтому я просто подумал, что упомянул IrelationalationoPerator.equals.. Отказ Я никогда не тестировал, чтобы увидеть, если этот метод отличится в толерании кластера пространственных ссылок на геометрию. Это может быть отрегулировано с использованием IspatialreferenceTolerance.xytolerance..

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top