Композиция против наследования для провайдеров Equality & Hashcode - PullRequest
3 голосов
/ 08 апреля 2009

При сравнении сущностей и совокупных корней я использую азбуку, которую я позаимствовал у Орен Эйни: Равенство общих сущностей . Для ценностных объектов я был одинаково гениален. Я использовал ABC объекта значения Джимми Богарда: Равенство общего значения объекта

Теперь мой вопрос; следует ли мне отдавать предпочтение наследованию этих ABC или, возможно, я должен использовать общий равенство / компаратор и составлять вместо этого вышеупомянутое поведение? Я намерен повторно использовать приведенные выше реализации равенства.

Я думаю, что это возвращается к System.Object, имеющему реализацию Equals по умолчанию, которая делает язык чертовски простым в использовании, но также предлагает интересные затруднения. Джон Скит подробно останавливается здесь: Методы сравнения

Может кто-нибудь придумать какие-нибудь плюсы или минусы?

  • Наследовать Азбуку проще и предлагает оператору перегрузки из коробка.
  • Должен ли я «тащить» два абстрактных занятия со мной так много? Это делает мой график наследования более сложный / добавляет сцепление.
  • Я мог бы использовать DI для составления равенства провайдеры?

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

1 Ответ

0 голосов
/ 11 июля 2009

Это действительно не отвечает на ваш вопрос (извините!), Но я думаю, что это проект, который пытается помочь с некоторыми из вопросов, которые у вас есть здесь. Некоторое время назад я написал этот материал, но с тех пор ничего не сделал.

Проект называется Essence (http://essence.codeplex.com/), и он использует библиотеки System.Linq.Expression для генерации (на основе атрибутов) стандартных представлений Equals / GetHashCode / CompareTo / ToString, а также возможности создать классы IEqualityComparer и IComparer на основе списка аргументов. (У меня также есть некоторые дополнительные идеи, но я хотел бы получить обратную связь от сообщества, прежде чем продолжать слишком много дальше.)

(Это означает, что он почти такой же быстрый, как и рукописный - основной, где это не так, является CompareTo (); потому что в Linq.Expressions нет понятия переменной в версии 3.5 - поэтому вы должны вызывать CompareTo () для базового объекта дважды, когда вы не получаете совпадение. Использование расширений DLR для Linq.Expressions решает эту проблему. Полагаю, я мог бы использовать emit il, но меня это не вдохновило в то время.)

Это довольно простая идея, но я не видел, чтобы это было сделано раньше.

Теперь дело в том, что я как бы потерял интерес к его полировке (что включало бы написание статьи для codeproject, документирование некоторого кода и т. П.), Но я мог бы убедить вас сделать это, если вы чувствуете это будет что-то интересное.

(На сайте codeplex нет загружаемого пакета; просто перейдите к исходному коду и возьмите его - о, он написан на f # (хотя весь тестовый код на c #), так как это было тем, что мне было интересно изучать .)

В любом случае, вот несколько примеров c # из моих тестовых примеров.

    // --------------------------------------------------------------------
    // USING MY ESSENCE LIBRARY:
    // --------------------------------------------------------------------
    [EssenceClass(UseIn = EssenceFunctions.All)]
    public class TestEssence : IEquatable<TestEssence>, IComparable<TestEssence>
    {
        [Essence(Order=0, Format="i={0},")]           public int MyInt           { get; set; }
        [Essence(Order=1, Format="s={0},")]           public string MyString     { get; set; }
        [Essence(Order=2, Format="d={0:yyyy-MM-dd}")] public DateTime MyDateTime { get; set; }

        public override int GetHashCode()                                { return Essence<TestEssence>.GetHashCodeStatic(this); }
        public override string ToString()                                { return Essence<TestEssence>.ToStringStatic(this); }
        public int CompareTo(TestEssence other)                          { return Essence<TestEssence>.CompareToStatic(this, other); }

        public static bool operator ==(TestEssence lhs, TestEssence rhs) { return Essence<TestEssence>.EqualsStatic(lhs, rhs); }
        public override bool Equals(object obj)                          { return this == (TestEssence)obj; }
        public bool Equals(TestEssence other)                            { return this == other; }
        public static bool operator !=(TestEssence lhs, TestEssence rhs) { return !(lhs == rhs); }
    }

    // --------------------------------------------------------------------
    // EQUIVALENT HAND WRITTEN CODE:
    // --------------------------------------------------------------------
    public class TestManual
    {
        public int MyInt;
        public string MyString;
        public DateTime MyDateTime;

        public override int GetHashCode()
        {
            var x = MyInt.GetHashCode();
            x *= Essence<TestEssence>.HashCodeMultiplier;
            x ^= (MyString == null) ? 0 : MyString.GetHashCode();
            x *= Essence<TestEssence>.HashCodeMultiplier;
            x ^= MyDateTime.GetHashCode();
            return x;
        }

        public static bool operator ==(TestManual lhs, TestManual rhs)
        {
            if (ReferenceEquals(lhs, null))
            {
                if (ReferenceEquals(rhs, null))
                    return true;
                return false;
            }
            if (ReferenceEquals(rhs, null))
                return false;
            if (ReferenceEquals(lhs, rhs))
                return true;
            if (typeof(TestManual) != rhs.GetType())
                return false;

            return lhs.MyInt == rhs.MyInt
                && lhs.MyString == rhs.MyString
                && lhs.MyDateTime == rhs.MyDateTime;
        }

        public override bool Equals(object obj)                 { return this == obj as TestManual; }
        public bool Equals(TestManual other)                    { return this == other; }
        public static bool operator !=(TestManual lhs, TestManual rhs) { return !(lhs == rhs); }

        public override string ToString()
        {
            if (MyString == null)
                return string.Format("i={0},d={1:yyyy-MM-dd}", MyInt, MyDateTime);

            return string.Format("i={0},s={1},d={2:yyyy-MM-dd}", MyInt, MyString, MyDateTime);
        }

        public int CompareTo(TestManual other)
        {
            if (other == null)
                return 1;
            if (ReferenceEquals(this, other))
                return 0;

            int result = 0;

            result = MyInt.CompareTo(other.MyInt);
            if (result != 0) return result;
            result = MyString.CompareTo(other.MyString);
            if (result != 0) return result;
            result = MyDateTime.CompareTo(other.MyDateTime);
            if (result != 0) return result;

            return result;
        }
    }

    // --------------------------------------------------------------------
    // --------------------------------------------------------------------
    // ALTERNATIVE USAGE
    // --------------------------------------------------------------------
    // --------------------------------------------------------------------

    class Simple
    {
        public Simple(int value) { Value1 = value; }
        public Simple(int value1, int value2) { Value1 = value1; Value2 = value2; }
        public readonly int Value1;
        public readonly int Value2;
    }

    [Test]
    public void TestReverseForwardString()
    {
        var _11 = new Simple(1, 1);
        var _12 = new Simple(1, 2);
        var _21 = new Simple(2, 1);
        var _22 = new Simple(2, 2);

        var items = new[] { _11, _12, _21, _22 };
        var reverseComparer = Essence<Simple>.CreateComparer("-Value1", "Value2");

        Array.Sort(items, reverseComparer);

        Assert.AreSame(_21, items[0]);
        Assert.AreSame(_22, items[1]);
        Assert.AreSame(_11, items[2]);
        Assert.AreSame(_12, items[3]);
    }

    [Test]
    public void TestReverseForwardLambda()
    {
        var _11 = new Simple(1, 1);
        var _12 = new Simple(1, 2);
        var _21 = new Simple(2, 1);
        var _22 = new Simple(2, 2);

        var items = new[] { _11, _12, _21, _22 };
        var reverseComparer = Essence<Simple>.CreateComparer(x => x.Action.ReverseNext, x => x.Member.Value1, x => x.Member.Value2);

        Array.Sort(items, reverseComparer);

        Assert.AreSame(_21, items[0]);
        Assert.AreSame(_22, items[1]);
        Assert.AreSame(_11, items[2]);
        Assert.AreSame(_12, items[3]);
    }

Веселись!

Paul.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...