Как сделать абстрактный базовый класс IComparable, который не сравнивает два отдельных унаследованных класса? - PullRequest
8 голосов
/ 09 января 2010

(C #, VS2008) В программе, над которой я работаю, у меня есть много объектов, каждый из которых имеет идентификатор и реализует IComparable, так что списки <> различных объектов легко доступны для поиска по идентификатору. Поскольку я ненавижу копировать / вставлять код, я решил абстрагировать эту функциональность до базового класса, например:

using System;

namespace MyProg.Logic
{
    abstract class IDObject : IComparable<IDObject> 
    {
        private int miID;

        public int ID
        {
            get { return miID; }
            set { miID = value; }
        }

        public IDObject(int ID)
        {
            miID = ID;
        }

        #region IComparable<IDObject> Members

        int IComparable<IDObject>.CompareTo(IDObject other)
        {
            return miID.CompareTo(other.miID);
        }

        #endregion
    }
}

Недостаток, который я вижу, состоит в том, что два отдельных класса, каждый из которых наследует его, будут напрямую сопоставимы с использованием .CompareTo (), и я надеялся добиться того, чтобы каждый класс, который наследовал от IDObject, был сопоставим только другим классам точно такого же класса , Так что я надеялся выяснить, как это сделать, и придумал это

using System;

namespace MyProg.Logic
{
    abstract class IDObject : IComparable<T> where T : IDObject
    {
        private int miID;

        public int ID
        {
            get { return miID; }
            set { miID = value; }
        }

        public IDObject(int ID)
        {
            miID = ID;
        }

        #region IComparable<T> Members

        int IComparable<T>.CompareTo(T other)
        {
            return miID.CompareTo(other.miID);
        }

        #endregion
    }
}

Но это дает ошибку компиляции «Ограничения не допускаются для неуниверсальных объявлений»

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

Ответы [ 2 ]

12 голосов
/ 09 января 2010

Вы можете использовать шаблон с любопытством повторяющихся шаблонов для решения этой проблемы.

abstract class Base<T> : IComparable<T> where T : Base<T> {
    public int Rank { get; set; } // Order instances of derived type T by Rank
    public int CompareTo(T other) { return Rank.CompareTo(other.Rank); }
}
class Foo : Base<Foo> {}
class Bar : Base<Bar> {}

static class Program {
   static void Main() {
       var foo1 = new Foo { Rank = 1 };
       var foo2 = new Foo { Rank = 2 };
       var bar1 = new Bar { Rank = 1 };
       var bar2 = new Bar { Rank = 2 };

       Console.WriteLine(foo1.CompareTo(foo2));
       Console.WriteLine(bar2.CompareTo(bar1));

       //error CS1503: Argument '1': cannot convert from 'Bar' to 'Foo'
       //Console.WriteLine(foo1.CompareTo(bar1));
   }
}
2 голосов
/ 09 января 2010

Я думаю, что у вас есть большие проблемы, чем просто проверка того, что типы производных классов одинаковы. Вы также возлагаете на производный класс ответственность за генерацию уникального идентификатора. Это требует, чтобы производный класс знал, какие другие идентификаторы были назначены ранее. Реально, это требует фабрики классов. Вам нужно будет применить это, сделав конструктор вашего абстрактного класса защищенным.

Не очень практично. Если идентификатор является просто непрозрачным числом, которое устанавливает идентичность объекта, тогда рассмотрите возможность назначения идентификатора самостоятельно. Используйте статический член для отслеживания последнего назначенного. Теперь все становится просто, и вам больше не нужно беспокоиться о производных типах классов.

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