Является ли Dictionary <string, object> лучшим способом передать неизвестную коллекцию переменных конструктору? - PullRequest
2 голосов
/ 26 июня 2010

У меня есть несколько «элементов раздела» (урок, информация), которые наследуются от общего типа SectionItem.Различные типы SectionItems разделяют некоторые , но не все свойства.

Я нашел, что лучший способ передать параметры каждому типу объекта - это упаковать их все в Dictionary<string, object>, а затем позволить базовому классу SectionItem распаковать common единиц, и каждый наследующий класс распаковывает специфичные единицы.

Это работает достаточно хорошо, но это все очень на C # 2, так как я буду ловить ошибки только во время выполнения, а не во время компиляции.Есть ли способ сделать это более элегантно, возможно, с помощью дженериков?

альтернативный текст http://www.deviantsart.com/upload/1hqkaoc.png

using System;
using System.Collections.Generic;
using System.Text;

namespace TestPass234
{
    class Program
    {
        static void Main(string[] args)
        {
            List<SectionItem> sectionItems = new List<SectionItem>();

            {
                Dictionary<string, object> vars = new Dictionary<string, object>();
                vars.Add("sectionNumber", 1);
                vars.Add("title", "Lesson #1");
                vars.Add("startDate", new DateTime(2008, 12, 25));
                List<Flashcard> flascards = new List<Flashcard>();
                flascards.Add(new Flashcard { Question = "What color is the sky?", Answer = "blue" });
                flascards.Add(new Flashcard { Question = "What color is the sun?", Answer = "yellow" });
                vars.Add("flashcards", flascards);
                SectionItem sectionItem = SectionItem.Instantiate("lesson", vars);
                sectionItems.Add(sectionItem);
            }

            {
                Dictionary<string, object> vars = new Dictionary<string, object>();
                vars.Add("title", "Info #1");
                vars.Add("content", "This is info number one.");
                SectionItem sectionItem = SectionItem.Instantiate("info", vars);
                sectionItems.Add(sectionItem);
            }

            foreach (var sectionItem in sectionItems)
            {
                Console.WriteLine(sectionItem.Render());
            }
            Console.ReadLine();
        }
    }

    public class SectionItem
    {
        protected string _title;

        public SectionItem()
        { }

        public SectionItem(Dictionary<string, object> vars)
        {
            _title = Convert.ToString(vars["title"]);
        }

        public static SectionItem Instantiate(string idCode, Dictionary<string, object> vars)
        {
            switch (idCode)
            {
                case "lesson":
                    return new SectionItemLesson(vars);
                case "info":
                    return new SectionItemInfo(vars);
                default:
                    return new SectionItem();
            }
        }

        public virtual string Render()
        {
            return "undefined section item";
        }

    }


    public class SectionItemLesson : SectionItem
    {
        private int _sectionNumber;
        private DateTime _startDate;
        private List<Flashcard> _flashcards = new List<Flashcard>();

        public SectionItemLesson(Dictionary<string, object> vars) : base(vars)
        {
            _sectionNumber = Convert.ToInt32(vars["sectionNumber"]);
            _startDate = Convert.ToDateTime(vars["startDate"]);
            _flashcards = vars["flashcards"] as List<Flashcard>;
        }

        public override string Render()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(String.Format(">>> {0}. {1} (Starts {2:ddd, MMM d, yyyy})", _sectionNumber, _title, _startDate));
            foreach (var flashcard in _flashcards)
                sb.AppendLine("    - " + flashcard.Render());
            return sb.ToString();
        }
    }

    public class SectionItemInfo : SectionItem
    {
        private string _content;

        public SectionItemInfo(Dictionary<string, object> vars)
            : base(vars)
        {
            _content = Convert.ToString(vars["content"]);
        }

        public override string Render()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(String.Format(">>> {0}", _title));
            sb.AppendLine(String.Format("    {0}", _content));
            return sb.ToString();
        }
    }

    public class Flashcard
    {
        public string Question { get; set; }
        public string Answer { get; set; }

        public string Render()
        {
            return "Q: " + Question + " A: " + Answer;
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 26 июня 2010

Можете ли вы просто создать класс «параметров» для каждого класса SectionItem?

public class SectionItemParameters
{
    public string Title { get; set; }
}

public class SectionItemLessonParameters
    : SectionItemParameters
{
    public int SectionNumber { get; set; }
    public DateTime StartDate { get; set; }
    public List<Flashcard> Flashcards { get; set; }
}

public class SectionItemInfoParameters
    : SectionItemParameters
{
    public string Content { get; set; }
}

Тогда каждый класс в иерархии может получить свои параметры в строго типизированном объекте.Ваш фабричный метод Instantiate будет принимать SectionItemParameters и приводить к типу, соответствующему вызываемому конструктору.

0 голосов
/ 26 июня 2010

Если набор возможных имен известен во время компиляции и с использованием C # 4, вы можете использовать стандартные / необязательные параметры в конструкторе.Если допустимы только определенные комбинации (например, только «Foo», если не указаны ни «Bar», ни «Baz»), вам все равно понадобятся проверки во время выполнения.

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

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