Dictionary <string,object>是将未知变量集合传递给构造函数的最佳方法吗?</string,object>

时间:2010-06-26 10:35:54

标签: c# generics oop dictionary

我有许多“section items”(Lesson,Info),它继承自常见类型SectionItem。各种类型的SectionItem共享一些但不是所有属性。

我发现将参数传递给每种对象的最佳方法是将它们全部打包在 Dictionary<string, object> 中,然后让基类SectionItem解压缩 common < / strong> ones,每个继承类解包特定的

这个工作得很好,但这都是C#2,因为我只会在运行时捕获错误,而不是在编译期间。有没有办法用泛型更优雅地做到这一点?

alt text 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 个答案:

答案 0 :(得分:2)

你能为每个SectionItem类创建一个'parameters'类吗?

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并强制转换为正在调用的构造函数的相应类型。

答案 1 :(得分:0)

如果在编译时已知可能的名称集并使用C#4,则可以在构造函数上使用default / optional参数。如果只有某些组合有效(例如,如果既没有提供“Bar”和“Baz”,则只提供“Foo”),那么你仍然需要运行时检查。

但如果名称集是真正动态的,那么只有字典或匿名类型的选项(并使用反射来提取正文中的名称集)。