Проблема дизайна в C #: Дженерики или полиморфизм или оба? - PullRequest
1 голос
/ 29 апреля 2011

Мне нужна помощь в решении проблемы с дизайном.Я пытаюсь добиться этого:

У меня есть основной класс с именем Document.Этот класс имеет список классов атрибутов.Эти классы атрибутов имеют некоторые общие свойства, такие как Identity и Name, но они отличаются одним свойством, которое я называю Value.Тип Value отличается для каждого отдельного класса Attribute и имеет тип string, integer, List, DateTime, float, List, а также классы, состоящие из нескольких свойств.В качестве примера можно привести класс, который я бы назвал PairAttribute, у которого есть 2 свойства: Title и Description.

Чего я хочу добиться, так это безопасности типов для свойства Value дочерних классов Attribute, и эти дочерние классы должны иметь возможностьбыть добавлен в список атрибутов в классе документа.Я мог бы создать только один класс Attribute, у которого есть свойство Value объекта type и что с ним покончено, но это именно то, чего я стараюсь избегать.

Должны быть размещены общие свойства (Identity и Name).в базовом классе, я думаю, давайте назовем этот класс AttributeBase.Но я хочу иметь дочерний класс, скажем StringAttribute, где свойство Value имеет тип string, класс IntegerAttribute, где свойство Value имеет тип Integer, StringListAttribute, где свойство Value имеет тип List, класс PairAttribute, где Valueкласс с несколькими свойствами и т. д.

Знаете, как я могу это реализовать?Это решение, к которому я должен стремиться, или это лучшие способы решения проблемы безопасности этого типа?Буду признателен за примеры кода для пояснения:)

Ответы [ 2 ]

5 голосов
/ 29 апреля 2011

Вы не указываете язык, но функция, описываемая термином «дженерики» (используемая в Java и C #), часто называется « параметрический полиморфизм » в других языках (таких как ML и Haskell ). И наоборот, общее значение « полиморфизм » в Java и C # на самом деле более точно называется « полиморфизм подтипа ».

Суть в том, используете ли вы полиморфизм подтипа или параметрический полиморфизм, в любом случае ваша задача требует полиморфизма, поэтому я думаю, что вы на правильном пути.

Вопрос действительно сводится к следующему: когда параметрический полиморфизм лучше полиморфизма подтипа? Ответ на самом деле довольно прост: когда требуется написать меньше кода.

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

1 голос
/ 29 апреля 2011

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

    public interface IAttribute {
        string Identity { get; set; }
        string Name { get; set; }
        T GetValue<T>();
    }

    public class Attribute<T> : IAttribute
    {

        public string Identity { get; set; }
        public string Name { get; set; }
        public T Value { get; set; }
        public Tret GetValue<Tret>() {
            return (Tret)(Object)Value;
        }
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            List<IAttribute> lst = new List<IAttribute>();
            Attribute<string> attr1 = new Attribute<string>();
            attr1.Value = "test";

            Attribute<int> attr2 = new Attribute<int>();
            attr2.Value = 2;

            lst.Add(attr1);
            lst.Add(attr2);

            string attr1val = lst[0].GetValue<string>();
            int attr2val = lst[1].GetValue<int>();

        }
    }

(Tret) (Object) на самом деле не меняет тип, а только блокирует T, а (Tret) распаковывает значениебез использования средних переменных.Это, конечно, потерпит неудачу, если вы пропустите правильный тип при вызове GetValue<type>().Даже если совместимые типы отправляются, например, Value является целым числом, а вы делаете GetValue<double>() ->, потому что распаковка целого числа в двойное недопустима.

Упаковка / распаковка не так быстра, как приведение, но она гарантирует безопасностьсохранились, и, насколько мне известно, нет никакого способа использовать дженерики с интерфейсом, известным во время компиляции, каким-либо другим способом.

Так что это должно быть безопасно для типов ... и без большого количества кода.

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