【问题标题】:C# Instantiate derived class from base constructor based on parameter typeC#根据参数类型从基构造函数实例化派生类
【发布时间】:2016-11-11 16:09:05
【问题描述】:

我有以下模型(简化):

数据库模型:

public abstract class Question
{
    public int Id { get; set; }
    public string Text { get; set; }
}

public class QuestionA : Question
{
    public bool OptionA { get; set; }
}

public class QuestionB : Question
{
    public int OptionB { get; set; }
}

查看模型:

public abstract class QuestionModel
{
    public string Text { get; set; }

    protected QuestionModel(Question question)
    {
        Text = question.Text;
    }
}

public class QuestionAModel : QuestionModel
{
    public bool OptionA { get; set; }

    public QuestionAModel(QuestionA questionA) : base(questionA)
    {
        OptionA = questionA.OptionA;
    }
}

public class QuestionBModel : QuestionModel
{
    public int OptionB { get; set; }

    public QuestionBModel(QuestionB questionB) : base(questionB)
    {
        OptionB = questionB.OptionB;
    }
}

基本上是将数据库实体映射到视图模型,例如,这个控制器:

public class SomeController : Controller
{
    public JsonResult Get()
    {
        // Simulating questions from the database
        var questions = new List<Question>
        {
            new QuestionA { Id = 1, OptionA = true, Text = "fooA" },
            new QuestionB { Id = 1, OptionB = 1, Text = "fooB" }
        };

        var model = questions.Select(q => new QuestionModel(q)).ToList();

        return Json(model);
    }
}

这显然不能编译,因为new QuestionModel(q)

我知道数据库中每个问题的类型,如何创建每个问题实体的派生问题模型?

谢谢大家!!

【问题讨论】:

    标签: c# hierarchy


    【解决方案1】:

    创建一个factory class,而不是调用构造函数,它将根据您必须创建的对象的类型提供正确的实现。

    请注意,在调用工厂之前,您必须从数据库中具体化您的对象:

    var model = questions.ToList().Select(q => QuestionFactory.CreateQuestion(q));
    

    【讨论】:

    • 很好,我现在就试试这个!
    【解决方案2】:

    在尝试为您的问题寻找替代解决方案时,我遇到了一个问题,希望有人可以为我解答。

    下面的代码工作得很好,我声明了一个 QuestionA 对象并创建了一个上述类型 (A) 的 QuestionModel,最后我将它添加到通用 QuestionModel 类型的列表中。

    QuestionA qA = new QuestionA { Id = 1, OptionA = true, Text = "fooA" };
    List<QuestionModel> lst = new List<QuestionModel>();
    lst.Add(new QuestionAModel(qA));
    

    但是,据说这段代码遵循相同的逻辑,但我无法编译它

    List<QuestionModel> model = new List<QuestionModel>();
    questions.ForEach(q => model.Add(q.GetType().Equals(typeof(QuestionA)) ?
         new QuestionAModel((QuestionA)q) : new QuestionBModel((QuestionB)q)));
    

    对于偏离 OP 的问题,我深表歉意

    编辑:因此,从技术上讲,以下代码将使您能够创建通用 QuestionModel 列表,而无需修改类

    var questions = new List<Question>
    {
       new QuestionA { Id = 1, OptionA = true, Text = "fooA" },
       new QuestionB { Id = 1, OptionB = 1, Text = "fooB" }
    };
    
    List<QuestionModel> model = new List<QuestionModel>();
    questions.ForEach(q => model.Add(q.GetType().Equals(typeof(QuestionA)) ?
                (QuestionModel)(new QuestionAModel((QuestionA)q)) : new QuestionBModel((QuestionB)q)));
    

    【讨论】:

    • 一个答案answers一个问题。这不是一个答案。如果您有问题但没有答案,请提出一个问题。
    • @InBetween 我认为它是相关的,因为通过解决这个问题,您也可以回答 OP 的问题。
    • 相关与否,都不是问题。答案是为了回答,而不是添加“相关”问题。
    • 话虽如此,您的问题根本不相关。您的代码无法编译只是因为条件表达式找不到有效类型;明确告诉编译器条件表达式的类型可以解决问题:questions.ForEach(q =&gt; model.Add(q.GetType().Equals(typeof(QuestionA)) ? (QuestionModel)(new QuestionAModel((QuestionA)q)) : new QuestionBModel((QuestionB)q))); 编译得很好。
    • @InBetween 谢谢,它现在按预期工作,我没想到您添加的 (QuestionModel) 演员的定位,因为它似乎只适用于条件输出的一半。我的回答现在应该对 OP 有用。
    猜你喜欢
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 2012-07-05
    • 2021-02-14
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    相关资源
    最近更新 更多