Правильно-ли так реализовать методы сравнения ???
От: Аноним  
Дата: 27.07.10 11:46
Оценка:
Поскольку достало переписывать одно и то-же, решил вынести реализацию таких методов как Equals(object), Equals(T), CompareTo(T) в отдельный абстрактный класс и наследоваться от него:
    public abstract class Comparers<T> : IComparable<T>, IEquatable<T>
        where T: class
    {
        //Собственно переопределением этого метода в производном классе и 
        //заканчивается реализация всех методов и операторов сравнения...
        protected abstract int Comparer(T other);

        public int CompareTo(T other)
        {
            //Cсылка null...
            if (object.ReferenceEquals(other, null)) return 1;

            //Ссылки указывают на один объект...
            if (ReferenceEquals(this, other)) return 0;

            return
                Comparer(other);
        }

        public bool Equals(T other)
        {
            return CompareTo(other) == 0;
        }

        public override bool Equals(object obj)
        {
            //При obj == null, obj is JobSchedule == false
            if (obj is T)
                return Equals((T)obj);

            return false;
        }

        //Позволяет реализовать оператор == в производном классе просто вызвав в
        //нём этот метод, т.к. выполняет все необходимые проверки и сравнения.
        protected static bool operatorEqual(T op1, T op2)
        {
            //Возвращает true - если op1 и op2 == null или если op1 и op2 указывают на один обьект.
            if (object.ReferenceEquals(op1, op2)) return true;

            //Если op1 == null, то op2 != null, иначе мы бы не преодолели предыдущего условия.
            if (object.ReferenceEquals(op1, null)) return false;

            return op1.Equals(op2);
        }
    }

    public class TestListItem : Comparers<TestListItem>
    {
        public int ID { get; set; }

        public string Caption { get; set; }

        public TestListItem Empty
        {
            get { return new TestListItem(); }
        }

        protected override int Comparer(TestListItem other)
        {
            if (ID != other.ID) return ID - other.ID;

            if (Caption.Length != other.Caption.Length)
                return Caption.Length > other.Caption.Length ? 1 : -1;

            return 
                string.Compare(Caption, other.Caption);
        }

        public static bool operator ==(TestListItem op1, TestListItem op2)
        {
            return operatorEqual(op1, op2);
        }

        public static bool operator !=(TestListItem op1, TestListItem op2)
        {
            return !(op1 == op2);
        }

        public override int GetHashCode()
        {
            return ID ^ Caption.Length;
        }
    }

Как вы думаете, правильно-ли так делать и какими проблемами, кроме предупреждений компилятора , это может обернуться
Re: Правильно-ли так реализовать методы сравнения ???
От: _FRED_ Черногория
Дата: 27.07.10 12:25
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Поскольку достало переписывать одно и то-же, решил вынести реализацию таких методов как Equals(object), Equals(T), CompareTo(T) в отдельный абстрактный класс и наследоваться от него:


А>Как вы думаете, правильно-ли так делать и какими проблемами, кроме предупреждений компилятора , это может обернуться

Всегда, когда можно обойтись без наследования, так поступить и стоит. В данном случае можно как-то так:

  public sealed class TestListItem : IEquatable<TestListItem>, IComparable<TestListItem>
  {
    private static readonly ComparerBuilder<TestListItem> ComparerBuilder
        = new ComparerBuilder<TestListItem>()
        .Add(x => x.ID)
        .Add(x => x.Caption);
    private static readonly IEqualityComparer<TestListItem> MyEqualityComparer = ComparerBuilder.ToEqualityComparer();
    private static readonly IComparer<TestListItem> MyComparer = ComparerBuilder.ToComparer();

    public int ID { get; set; }

    public string Caption { get; set; }

    public override bool Equals(object obj) {
      return Equals(obj as TestListItem);
    }

    public override int GetHashCode() {
      return MyEqualityComparer.GetHashCode(this);
    }

    public bool Equals(TestListItem other) {
      return MyEqualityComparer.Equals(this, other);
    }

    public int CompareTo(TestListItem other) {
      return MyComparer.Compare(this, other);
    }

    public static bool operator ==(TestListItem left, TestListItem right) {
      return Equals(left, right);
    }

    public static bool operator !=(TestListItem left, TestListItem right) {
      return !(left == right);
    }

    public static bool operator <(TestListItem left, TestListItem right) {
      return MyComparer.Compare(left, right) < 0;
    }

    public static bool operator <=(TestListItem left, TestListItem right) {
      return MyComparer.Compare(left, right) <= 0;
    }

    public static bool operator >(TestListItem left, TestListItem right) {
      return !(left <= right);
    }

    public static bool operator >=(TestListItem left, TestListItem right) {
      return !(left < right);
    }
  }


Надо быт очень осторожным, переопределяя логику сравнения для типов, откоытых для расширения.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Правильно-ли так реализовать методы сравнения ???
От: Аноним  
Дата: 27.07.10 12:55
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>
_FR>  public sealed class TestListItem : IEquatable<TestListItem>, IComparable<TestListItem>
_FR>  {
_FR>    private static readonly ComparerBuilder<TestListItem> ComparerBuilder
_FR>        = new ComparerBuilder<TestListItem>()
_FR>        .Add(x => x.ID)
_FR>        .Add(x => x.Caption);
_FR>    private static readonly IEqualityComparer<TestListItem> MyEqualityComparer = ComparerBuilder.ToEqualityComparer();
_FR>    private static readonly IComparer<TestListItem> MyComparer = ComparerBuilder.ToComparer();
_FR>  }
_FR>


_FR>Надо быт очень осторожным, переопределяя логику сравнения для типов, открытых для расширения.


Тут я кое-чего не понял.
1) Что это такое:
    private static readonly ComparerBuilder<TestListItem> ComparerBuilder
        = new ComparerBuilder<TestListItem>()
        .Add(x => x.ID)
        .Add(x => x.Caption);

2) Класс запечатывать не стоит, от него наследуются ещё три других;
3) На счет наследования. Вы имеет ввиду, что лучше реализовать "сравниватели" в отдельном классе, и явно их вызывать в соответствующих реализациях методов и операторов сравнений класса TestListItem?
Re[3]: Правильно-ли так реализовать методы сравнения ???
От: _FRED_ Черногория
Дата: 27.07.10 13:15
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Тут я кое-чего не понял.

А>1) Что это такое:
А>    private static readonly ComparerBuilder<TestListItem> ComparerBuilder
А>        = new ComparerBuilder<TestListItem>()
А>        .Add(x => x.ID)
А>        .Add(x => x.Caption);


"Секретный ингридиент", не суть важно. Смысл в том, что базу ради реализации сравнения заводить не стоит.

А>2) Класс запечатывать не стоит, от него наследуются ещё три других;


Надеюсь, вы представляете себе, какие могт быть сложности и непонятности и как надо реализовать проверки в данном случае.

А>3) На счет наследования. Вы имеет ввиду, что лучше реализовать "сравниватели" в отдельном классе, и явно их вызывать в соответствующих реализациях методов и операторов сравнений класса TestListItem?


В некоторых случаях — да, но не всегда. Смысл в том, что 1: не нужет базовый класс и 2: реализовывать ревенство через CompareTo() == 0 не всегда подходит и в общем виде не следует эти операции смешивать.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Правильно-ли так реализовать методы сравнения ???
От: Аноним  
Дата: 27.07.10 13:31
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>"Секретный ингридиент", не суть важно. Смысл в том, что базу ради реализации сравнения заводить не стоит.


Я имел ввиду:
        .Add(x => x.ID)
        .Add(x => x.Caption);


Меня именно синтаксис интересует...

А>>2) Класс запечатывать не стоит, от него наследуются ещё три других;


_FR>Надеюсь, вы представляете себе, какие могут быть сложности и непонятности и как надо реализовать проверки в данном случае.


Честно говоря не очень Откройте глаза
Re[5]: Правильно-ли так реализовать методы сравнения ???
От: _FRED_ Черногория
Дата: 27.07.10 13:49
Оценка:
Здравствуйте, Аноним, Вы писали:

_FR>>"Секретный ингридиент", не суть важно. Смысл в том, что базу ради реализации сравнения заводить не стоит.

А>Я имел ввиду:
А>        .Add(x => x.ID)
А>        .Add(x => x.Caption);

А>Меня именно синтаксис интересует...

метод Add имеет сигнатуру
public ComparerBuilder<T> Add<P>(Expression<Func<T, P>> expression, IEqualityComparer<P> equalityComparer = null, IComparer<P> comparer = null);

Почитайте про Lambda Expressions

А>>>2) Класс запечатывать не стоит, от него наследуются ещё три других;

_FR>>Надеюсь, вы представляете себе, какие могут быть сложности и непонятности и как надо реализовать проверки в данном случае.
А>Честно говоря не очень Откройте глаза

У вас, вы говорите, есть базовый класс и несколько наследников. Покажите, как вы собираетесь реализовывать Equals\GetHashCode, тогда и посмотрим
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Правильно-ли так реализовать методы сравнения ???
От: Аноним  
Дата: 29.07.10 14:10
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>У вас, вы говорите, есть базовый класс и несколько наследников. Покажите, как вы собираетесь реализовывать Equals\GetHashCode, тогда и посмотрим


Честно говоря, разбираться с Expression было очень лень, да и времени надо много. Поэтому решил для иллюстрации написать классы попроще и показать Вас, в надежде что вы ещё раз укажете мне на мои ошибки:
    class TwoDPoint : IComparable, IComparable<TwoDPoint>, IEquatable<TwoDPoint>
    {
        protected int x, y;

        public virtual int CompareTo(object obj)        //<<<---
        {
            Console.WriteLine("TwoDPoint.CompareTo(object)");

            if (object.ReferenceEquals(this, obj)) return 0;
            TwoDPoint other = obj as TwoDPoint;
            if (!object.Equals(other, null))
            {
                return x - other.x == 0 && y - other.y == 0 ? 0
                    : x - other.x > 0 || y - other.y > 0 ? 1 : -1;
            }

            return -1;
        }

        public int CompareTo(TwoDPoint other)
        {
            Console.WriteLine("TwoDPoint.CompareTo(TwoDPoint)");
            return CompareTo((object)other);
        }

        public override bool Equals(object obj)
        {
            Console.WriteLine("TwoDPoint.Equals(object)");
            return CompareTo(obj) == 0;
        }

        public bool Equals(TwoDPoint other)
        {
            Console.WriteLine("TwoDPoint.Equals(TwoDPoint)");
            return Equals((object)other);
        }

        public static bool operator ==(TwoDPoint op1, TwoDPoint op2)
        {
            Console.WriteLine("TwoDPoint.operator==");
            if (object.ReferenceEquals(op1, op2)) return true;
            if (object.ReferenceEquals(op1, null)) return false;
            return op1.Equals(op2);
        }

        public static bool operator !=(TwoDPoint op1, TwoDPoint op2)
        {
            Console.WriteLine("TwoDPoint.operator!=");
            return !(op1 == op2);
        }

        public override int GetHashCode()
        {
            return x ^ y;
        }
    }

    class ThreeDPoint : TwoDPoint, IComparable<ThreeDPoint>, IEquatable<ThreeDPoint>
    {
        int z;

        public override int CompareTo(object obj)
        {
            Console.WriteLine("ThreeDPoint.CompareTo(object)");
            
            if (object.ReferenceEquals(this, obj)) return 0;
            ThreeDPoint other = obj as ThreeDPoint;
            if (!object.Equals(other, null))
            {
                return base.CompareTo(obj) == 0 && z == other.z ? 0
                    : base.CompareTo(obj) > 0 || z - other.z > 0 ? 1 : -1;
            }

            return -1;
        }

        public int CompareTo(ThreeDPoint other)
        {
            Console.WriteLine("ThreeDPoint.CompareTo(ThreeDPoint)");
            return CompareTo((object)other);
        }

        public override bool Equals(object obj)
        {
            Console.WriteLine("ThreeDPoint.Equals(object)");
            return this.CompareTo(obj) == 0;
        }

        public bool Equals(ThreeDPoint other)
        {
            Console.WriteLine("ThreeDPoint.Equals(ThreeDPoint)");
            return this.Equals((object)other);
        }

        public static bool operator ==(ThreeDPoint op1, ThreeDPoint op2)
        {
            Console.WriteLine("ThreeDPoint.operator==");
            if (object.ReferenceEquals(op1, op2)) return true;
            if (object.ReferenceEquals(op1, null)) return false;
            return op1.Equals(op2);
        }

        public static bool operator !=(ThreeDPoint op1, ThreeDPoint op2)
        {
            Console.WriteLine("ThreeDPoint.operator!=");
            return !(op1 == op2);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() ^ z;
        }
    }
    static class Test
    {
        public static void Main()
        {
            ThreeDPoint three = new ThreeDPoint();
            TwoDPoint two = three as TwoDPoint;

            two.Equals(new object());
            Console.WriteLine();

            two.Equals(two);
            Console.WriteLine();

            two.CompareTo(new object());
            Console.WriteLine();

            two.CompareTo(two);
            Console.WriteLine();

            bool a = (two == new TwoDPoint());
            Console.WriteLine();

            bool b = (two != new TwoDPoint());
        }
    }

Сделал CompareTo виртуальным, чтобы код работал при обращении через ссылку на базовый класс.
Re[7]: Правильно-ли так реализовать методы сравнения ???
От: _FRED_ Черногория
Дата: 29.07.10 14:54
Оценка:
Здравствуйте, Аноним, Вы писали:

_FR>>У вас, вы говорите, есть базовый класс и несколько наследников. Покажите, как вы собираетесь реализовывать Equals\GetHashCode, тогда и посмотрим


А>Честно говоря, разбираться с Expression было очень лень, да и времени надо много. Поэтому решил для иллюстрации написать классы попроще и показать Вас, в надежде что вы ещё раз укажете мне на мои ошибки:


Help will always be given at Hogwarts to those who ask for it.
Re[6]: Правильно-ли так реализовать методы сравнения ???
От: Lloyd Россия  
Дата: 29.07.10 17:26
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>метод Add имеет сигнатуру

_FR>
_FR>public ComparerBuilder<T> Add<P>(Expression<Func<T, P>> expression, IEqualityComparer<P> equalityComparer = null, IComparer<P> comparer = null);
_FR>


А почему именно Expression? Разве Func-а недостаточно?
Re[8]: Правильно-ли так реализовать методы сравнения ???
От: Аноним  
Дата: 29.07.10 19:10
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>
  • Является ли валидным с вашей точки зрения то, что три равно двум?
    _FR>var two = new TwoDPoint();
    _FR>var three = new ThreeDPoint();
    _FR>Console.WriteLine("Is Two and Three equal? {0}", two == three);
    _FR>

    _FR>
  • Идеи наследования 3d точки от 2d точки, как и то, что эти типы являются классами, очень подозрительны. Если пример надуман, то реализации равенства на таком абстрактном примере неинтересна. Если не надуман, то чем оправдан?
    _FR>[/list]

    В математике, 2-х мерная точка, это 3-х мерная у которой координата по z всегда равна нулю. А одномерной точкой можно считать, точку имеющую только одну координату, а две другие равными нулю. Собственно от этого и отталкиваются в операциях над векторами, считая координату вектора по каждой оси отдельно. Ни что не мешает сделать 5-ти, 6-ти и N-мерную точку, т.к. точка это просто абстракция, а смысл в неё залить можно какой угодно. Например, такие многомерные пространства(из точек) часто используются в физике. А в теории суперструн, которая претендует сейчас на звание теории всего, многие исследуемые объекты имеют по 10-12 измерений.

    _FR>Не могли бы сравнить свой решение с тем и объяснить, чем ваше решение вам нравится больше?


    Что-бы разговор был более предметным так [1] я буду помечать в тексте вопросы на которые хотелось бы получить ответы

    Мысль о применении сторонних компараторов посетила сразу, но с толку сбил класс ComparerBuilder<T>. Я не знал его реализации и не сразу сообразил, что именно он делает. [1]Если я правильно понял, то Вы считаете, что такая реализация будет более правильной:
        static class EqualityComparers
        {
            public static bool TwoDPointEqualityComparer(TwoDPoint point1, TwoDPoint point2)
            {
                Console.WriteLine("TwoDPoint.EqualityComparer");
                if (object.ReferenceEquals(point1, point2)) return true;
                if (object.ReferenceEquals(point1, null) || 
                    object.ReferenceEquals(point2, null)) return false;
    
                return point1.X == point2.X && point1.Y == point2.Y;
            }
    
            public static bool ThreeDPointEqualityComparer(ThreeDPoint point1, ThreeDPoint point2)
            {
                Console.WriteLine("ThreeDPoint.EqualityComparer");
                if (object.ReferenceEquals(point1, point2)) return true;
                if (object.ReferenceEquals(point1, null) ||
                    object.ReferenceEquals(point2, null)) return false;
    
                return point1.X == point2.X && point1.Y == point2.Y && point1.Z == point2.Z;
            }
        }
    
        static class Comparers
        {
            public static int TwoDPointComparer(TwoDPoint point1, TwoDPoint point2)
            {
                Console.WriteLine("TwoDPoint.Comparer");
                if (object.ReferenceEquals(point1, point2)) return 0;
                if (object.ReferenceEquals(point1, null)) return -1;
                if (object.ReferenceEquals(point2, null)) return 1;
    
                return point1.X - point2.X == 0 && point1.Y - point2.Y == 0 
                    ? 0
                    : point1.X - point2.X > 0 || point1.Y - point2.Y > 0 ? 1 : -1;
            }
    
            public static int ThreeDPointComparer(ThreeDPoint point1, ThreeDPoint point2)
            {
                Console.WriteLine("ThreeDPoint.Comparer");
                if (object.ReferenceEquals(point1, point2)) return 0;
                if (object.ReferenceEquals(point1, null)) return -1;
                if (object.ReferenceEquals(point2, null)) return 1;
    
                return TwoDPointComparer(point1, point2) == 0 && point1.Z == point2.Z 
                    ? 0
                    : TwoDPointComparer(point1, point2) > 0 || point1.Z - point2.Z > 0 ? 1 : -1;
            }
        }
    
        class TwoDPoint : IComparable, IComparable<TwoDPoint>, IEquatable<TwoDPoint>
        {
            protected int x, y;
    
            public TwoDPoint(int xx = 0, int yy = 0)
            {
                x = xx;
                y = yy;
            }
    
            public int X { get { return x; } }
            public int Y { get { return y; } }
    
            public int CompareTo(TwoDPoint other)
            {
                Console.WriteLine("TwoDPoint.CompareTo(TwoDPoint)");
                return Comparers.TwoDPointComparer(this, other);
            }
    
            public virtual int CompareTo(object obj)
            {
                Console.WriteLine("TwoDPoint.CompareTo(object)");
                return CompareTo(obj as TwoDPoint);
            }
    
            public bool Equals(TwoDPoint other)
            {
                Console.WriteLine("TwoDPoint.Equals(TwoDPoint)");
                return EqualityComparers.TwoDPointEqualityComparer(this, other);
            }
    
            public override bool Equals(object obj)
            {
                Console.WriteLine("TwoDPoint.Equals(object)");
                return Equals(obj as TwoDPoint);
            }
    
            public static bool operator ==(TwoDPoint op1, TwoDPoint op2)
            {
                Console.WriteLine("TwoDPoint.operator==(TwoDPoint, TwoDPoint)");
                return Equals(op1, op2);
            }
    
            public static bool operator !=(TwoDPoint op1, TwoDPoint op2)
            {
                Console.WriteLine("TwoDPoint.operator!=(TwoDPoint, TwoDPoint)");
                return !(op1 == op2);
            }
    
            public override int GetHashCode()
            {
                return x ^ y;
            }
        }
    
        class ThreeDPoint : TwoDPoint, IComparable<ThreeDPoint>, IEquatable<ThreeDPoint>
        {
            int z;
    
            public ThreeDPoint(int xx = 0, int yy = 0, int zz = 0)
                : base(xx, yy)
            {
                z = zz;
            }
    
            public int Z { get { return z; } }
    
            public int CompareTo(ThreeDPoint other)
            {
                Console.WriteLine("ThreeDPoint.CompareTo(ThreeDPoint)");
                return Comparers.ThreeDPointComparer(this, other);
            }
    
            public override int CompareTo(object obj)
            {
                Console.WriteLine("ThreeDPoint.CompareTo(object)");
                return CompareTo(obj as ThreeDPoint);
            }
    
            public bool Equals(ThreeDPoint other)
            {
                Console.WriteLine("ThreeDPoint.Equals(ThreeDPoint)");
                return EqualityComparers.ThreeDPointEqualityComparer(this, other);
            }
    
            public override bool Equals(object obj)
            {
                Console.WriteLine("ThreeDPoint.Equals(object)");
                return Equals(obj as ThreeDPoint);
            }
    
            public static bool operator ==(ThreeDPoint op1, ThreeDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator==(ThreeDPoint, ThreeDPoint)");
                return Equals(op1, op2);
            }
    
            public static bool operator ==(ThreeDPoint op1, TwoDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator==(ThreeDPoint, TwoDPoint)");
                return Equals(op2, op1);
            }
    
            public static bool operator ==(TwoDPoint op1, ThreeDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator==(TwoDPoint, ThreeDPoint)");
                return Equals(op1, op2);
            }
    
            public static bool operator !=(ThreeDPoint op1, ThreeDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator!=(ThreeDPoint, ThreeDPoint)");
                return !(op1 == op2);
            }
    
            public static bool operator !=(ThreeDPoint op1, TwoDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator==(ThreeDPoint, TwoDPoint)");
                return !(op1 == op2);
            }
    
            public static bool operator !=(TwoDPoint op1, ThreeDPoint op2)
            {
                Console.WriteLine("ThreeDPoint.operator==(TwoDPoint, ThreeDPoint)");
                return !(op1 == op2);
            }
    
            public override int GetHashCode()
            {
                return base.GetHashCode() ^ z;
            }
        }

    Однако меня волнует один момент. Если нарисовать схему вызовов:
    operator!=(T,T) -> operator==(T,T) -> Equals(object) -> Equals(T) -> EqualityComparer
    CompareTo(T) -> Comparer

    то будет заметно, что в таком решении только Equals(object) является виртуальным. А это значит, что если сделать так:
    ThreeDPoint three = new ThreeDPoint();
    TwoDPoint two = three as TwoDPoint;
    two.Equals(three);
    two.CompareTo(three);

    то будут вызваны реализации методов класса TwoDPoint. В моем-же решении схема вызовов другая:
    operator!=(T,T) -> operator==(T,T) -> Equals(object) -> CompareTo(object)
    Equals(T) -> Equals(object)
    CompareTo(T) -> CompareTo(object)

    т.е. все вызовы идут через виртуальные методы, и такую проблему удается обойти. При этом я не спорю, что использовании сторонних компараторов делает код проще и безопаснее. [2] Я просто не понимаю, почему если метод CompareTo(object) и сторонний компаратор делают одно и то-же, почему нельзя всё замкнуть на CompareTo(object) если всё равно нет разницы
    Кроме того пока я всё это набирал, у меня возник ещё один вопрос. Существует проблемма связання с реализацией оператора == в цепочке наследования из нескольких классов. Например, есть базовый класс A и производный B. Тогда при реализации == в классе А прийдется реализовать один оператор вида operator==(A, A), а в производном классе B уже три оператора вида: operator==(A, B), operator==(B, A) и operator==(B, B). Рассуждая аналогичным образом для класса C наследника B, потребуется реализовать уже пять операторов. А для класса D наследника C уже девять !!!
    [3]Зачем их реализовывать, а как производить сравнения типа A == B или A == C? Определение оператора преобразования в/из базового класса в C# запрещены, поэтому выполняя сравнение A == B, будет вызван operator==(A, A), который сравнит общие для A и B поля и на этом основании сделает вывод о равенстве или не равенстве A и B, т.е. равными могут оказаться обьекты разных классов Что в некоторых случаях вообще неприемлемо! [4] В связи с этим вопрос как можно решить эту проблему Ведь если в цпочке наследования 5-ть классов, то в последнем может случиться, что понадобиться реализовать уже 11 операторов сравнения !!!
  • Re[9]: Правильно-ли так реализовать методы сравнения ???
    От: hardcase Пират http://nemerle.org
    Дата: 29.07.10 19:30
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>В математике, 2-х мерная точка, это 3-х мерная у которой координата по z всегда равна нулю.


    Если точек много и считать много, то объектами их делать лишь себе в убыток. Я бы сделал структурами и добавил операции приведения типов точек.
    /* иЗвиНите зА неРовнЫй поЧерК */
    Re[9]: Правильно-ли так реализовать методы сравнения ???
    От: Аноним  
    Дата: 29.07.10 19:42
    Оценка: :)
    Здравствуйте, Аноним, Вы писали:

    <skipped>

    У меня одно замечание. Если все выше написанное и есть источник вопроса, то какие <censored> компараторы и экспрешены? Вы же всего лишь координаты сравниваете!!11адинадин..

    Keep It Simple Stupid же И я совершенно не представляю в какой области математики имеет смысл отношение порядка для многомерных координат. Если у вас отдельный класс на каждое измерение и они могут (судя по вашему примеру, могут) равноправно присутствовать в одном выражении, может быть стоит попробовать использовать один класс с массивом координат.

    Если вышеприведенный код должен был лишь придать немного конкретики философским рассуждениям транзитивности реализации операторов сравнения, примите мои извинения за возможно резкие высказывания, продолжайте .
    Re[9]: Правильно-ли так реализовать методы сравнения ???
    От: samius Япония http://sams-tricks.blogspot.com
    Дата: 29.07.10 19:46
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>В математике, 2-х мерная точка, это 3-х мерная у которой координата по z всегда равна нулю. А одномерной точкой можно считать, точку имеющую только одну координату, а две другие равными нулю. Собственно от этого и отталкиваются в операциях над векторами, считая координату вектора по каждой оси отдельно.


    Согласно этой логике нужно наследовать 2х мерную точку от 3х мерной и (N-1)мерную от N-мерной в общем случае.

    Только причем тут наследование?

    Судя по интерфейсам, поддерживаемых классами, сравнивать разномерные точки не нужно, это просто побочный эффект наследования такой. Может ну его нафик, это наследование?
    Re[7]: Правильно-ли так реализовать методы сравнения ???
    От: _FRED_ Черногория
    Дата: 29.07.10 19:46
    Оценка:
    Здравствуйте, Lloyd, Вы писали:

    _FR>>метод Add имеет сигнатуру

    _FR>>public ComparerBuilder<T> Add<P>(Expression<Func<T, P>> expression, IEqualityComparer<P> equalityComparer = null, IComparer<P> comparer = null);


    L>А почему именно Expression? Разве Func-а недостаточно?


    А как обойтись делегатами? Колдунство с приведениями типов и рефлекшеном мне не нравится. Из expression я беру MemberExpression и строю выражения для сравнения, подсчёта хеша и сравнения. Методы To[…]Comparer() компилируют их в методы и создают/возвращают компараторы, которые Equals\GetHashCode\CompareTo переадрусуют этим методам.
    Help will always be given at Hogwarts to those who ask for it.
    Re[8]: Правильно-ли так реализовать методы сравнения ???
    От: Lloyd Россия  
    Дата: 29.07.10 19:51
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    L>>А почему именно Expression? Разве Func-а недостаточно?


    _FR>А как обойтись делегатами? Колдунство с приведениями типов и рефлекшеном мне не нравится. Из expression я беру MemberExpression и строю выражения для сравнения, подсчёта хеша и сравнения. Методы To[…]Comparer() компилируют их в методы и создают/возвращают компараторы, которые Equals\GetHashCode\CompareTo переадрусуют этим методам.


    Все-таки не до конца поятно, почему приведение типов — это колдунство, а работа с MemberExpression — нет?
    Может приведешь реализацию?
    Re[10]: Правильно-ли так реализовать методы сравнения ???
    От: Аноним  
    Дата: 29.07.10 19:59
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>Если вышеприведенный код должен был лишь придать немного конкретики философским рассуждениям транзитивности реализации операторов сравнения, примите мои извинения за возможно резкие высказывания, продолжайте .


    Так оно и есть
    Re[9]: Правильно-ли так реализовать методы сравнения ???
    От: _FRED_ Черногория
    Дата: 29.07.10 20:00
    Оценка:
    Здравствуйте, Lloyd, Вы писали:

    L>>>А почему именно Expression? Разве Func-а недостаточно?


    _FR>>А как обойтись делегатами? Колдунство с приведениями типов и рефлекшеном мне не нравится. Из expression я беру MemberExpression и строю выражения для сравнения, подсчёта хеша и сравнения. Методы To[…]Comparer() компилируют их в методы и создают/возвращают компараторы, которые Equals\GetHashCode\CompareTo переадрусуют этим методам.


    L>Все-таки не до конца поятно, почему приведение типов — это колдунство,


    Потому что, если сделать без такого билдера на Func<>, напрямую сравнив поля, то код будет работать потенциально сильно быстрее. С компиляцией выражений в код разницы практически никакой.

    L>а работа с MemberExpression — нет?


    Потому что "работа с MemberExpression" идёт только во время вызова Add. Один раз. При вызове To[…]Comparer() создаётся компаратор с уже скомпилированными методами, внутри которого никаких преобрахований типов и никакого рефлекшена нет — как будто код написан непосредственно в коде класса.

    L>Может приведешь реализацию?


    Обязательно, как только причешу. У меня недавно как раз эта идея появилась. Сейчас правда хеш считается глупо ксором всех полей, хочу добавить в него ещё перемешивание, но для "посмотреть" это, надеюсь, не принципиально :о)
    Help will always be given at Hogwarts to those who ask for it.
    Re[10]: Правильно-ли так реализовать методы сравнения ???
    От: Аноним  
    Дата: 29.07.10 20:03
    Оценка:
    Здравствуйте, samius, Вы писали:

    S>Согласно этой логике нужно наследовать 2х мерную точку от 3х мерной и (N-1)мерную от N-мерной в общем случае.


    Вы не правы. Наследуясь от 2-х мерной точки вы добавляете ещё одно измерение и она становиться 3-х мерной. Наследуясь от 3-х мерной, вы добавляете ещё одно измерение и т.д. В общем случае, N-мерная точка наследуется от (N-1)-мерной. Всё начинается с точки с одним измерением. Можно конечно создать массив измерений, но это уже надо смотреть по тому где такой класс будет применяться. Но всё это не очень важно, т.к. класс был приведен просто для иллюстрации идеи.
    Re[10]: Правильно-ли так реализовать методы сравнения ???
    От: Lloyd Россия  
    Дата: 29.07.10 20:05
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    _FR>Потому что, если сделать без такого билдера на Func<>, напрямую сравнив поля, то код будет работать потенциально сильно быстрее. С компиляцией выражений в код разницы практически никакой.


    L>>а работа с MemberExpression — нет?


    _FR>Потому что "работа с MemberExpression" идёт только во время вызова Add. Один раз. При вызове To[…]Comparer() создаётся компаратор с уже скомпилированными методами, внутри которого никаких преобрахований типов и никакого рефлекшена нет — как будто код написан непосредственно в коде класса.


    Т.е. речь прежде всего о перформансе? Тогда выбор понятен.
    Re[10]: Правильно-ли так реализовать методы сравнения ???
    От: Аноним  
    Дата: 29.07.10 20:09
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    _FR>Обязательно, как только причешу. У меня недавно как раз эта идея появилась. Сейчас правда хеш считается глупо ксором всех полей, хочу добавить в него ещё перемешивание, но для "посмотреть" это, надеюсь, не принципиально :о)


    Не принципиально. Дай код посмотреть
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.