C# 同一属性中的不同对象类型

C# 同一属性中的不同对象类型,c#,ravendb,C#,Ravendb,我在和RavenDb玩,我在做一些测验。有不同类型的问题: -多项选择(A、B、C或D?) -日期(您在哪一天…?) -数字(有多少…?) 我所做的是创建一个基类问题,带有一个属性Question,该属性包含用户给出的作为字符串的问题和答案列表 public class Question { public string Question { get; set; } public List<Answer> Answers { get; set; } } 我在这里要做的

我在和RavenDb玩,我在做一些测验。有不同类型的问题: -多项选择(A、B、C或D?) -日期(您在哪一天…?) -数字(有多少…?)

我所做的是创建一个基类问题,带有一个属性
Question
,该属性包含用户给出的作为字符串的问题和答案列表

public class Question
{
    public string Question { get; set; }
    public List<Answer> Answers { get; set; }
}
我在这里要做的是将答案保存为字符串,并保存类型(DateTime、float等),以便稍后对其进行解析


它很管用,但我不太喜欢。必须有另一种更好的方法。

您可以使用泛型。创建
TAnswer
的泛型类
Question
,其中
TAnswer
必须从抽象类
Answer
继承。特定问题类将从该类继承:

public abstract class Question<TAnswer> where TAnswer : Answer
{
    public Guid Id { get; set; }
    public string Question { get; set; }
    public List<TAnswer> Answers { get; set; }
}

public class DateQuestion : Question<DateAnswer>
{
    //...
}

如果要在同一属性中存储多个类型,则只需将该属性声明为公共基类型。在您的情况下,
对象
就可以了。序列化后,您将在json中获得额外的
$type
字段,这将允许将它们反序列化回正确的形式

让我们看看我能否就您的特定领域模型提供一些建议

  • 不要把可能的答案和实际的答案混淆起来。给这些不同的名字,让它们保持笔直。我将使用
    Choice
    表示问题的可能答案,并使用
    answer
    表示用户给出的实际答案

  • 注意聚合实体的位置。这些是最终在RavenDB中作为实际文档并获得Id的内容。在您的案例中,我只看到两个-
    问题
    考试

试试这个尺码:

public abstract class Question
{
    public string Id { get; set; }
    public string QuestionText { get; set; }
}

public class ValueQuestion : Question
{
    public object CorrectValue { get; set; }
}

public class RangeQuestion : Question
{
    public object MinCorrectValue { get; set; }
    public object MaxCorrectValue { get; set; }
}

public class MultipleChoiceQuestion : Question
{
    public int NumberOfChoicesAllowed { get; set; }
    public List<MultipleChoiceOption> Choices { get; set; }
}

public class MultipleChoiceOption
{
    public char Letter { get; set; }
    public bool Correct { get; set; }
    public object Value { get; set; }
}

public class EssayQuestion : Question
{
    public int MinAnswerLength { get; set; }
    public int MaxAnswerLength { get; set; }
}

public class Exam
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public DateTime Taken { get; set; }
    public decimal Score { get; set; }
    public List<Answer> Answers { get; set; }
}

public class Answer
{
    public string QuestionId { get; set; }
    public bool Correct { get; set; }
    public object Value { get; set; }
}

你为什么不“非常喜欢”?我想一定有更干净的解决办法。现在我必须解析每个答案来检查它是否正确,而不是直接比较它。谢谢你给出了令人难以置信的答案!我使用的是第一个建议,属性类型为
object
。但是,当检索答案时,如果它是日期时间,它不会将其识别为日期时间。虽然CreatedOn属性始终是DateTime,但它确实可以识别它。我在Raven Management Studio中查找了它,两个属性看起来完全相同。为什么RavenDb不承认答案是DateTime。我试过选角,但没用。有趣的是。。。看来它毕竟没有使用
$type
字段。可能是因为这些是基本类型。但它确实应该承认这是一个日期。我将向RavenDB团队报告这一点。但是-你确定要把它作为约会对象吗?我的意思是,如果你的问题的答案是一个日期,那么准确度不会达到一整天吗?您也可以将其存储为预设格式的字符串(可能是YYYY-MM-DD)。
public abstract class Answer {
    public Guid QuestionId { get; set; }
    public Guid UserId { get; set; }
}

public class MultipleChoiceAnswer :Answer {
    //...
}

public class DateAnswer : Answer {
    //...
}
public abstract class Question
{
    public string Id { get; set; }
    public string QuestionText { get; set; }
}

public class ValueQuestion : Question
{
    public object CorrectValue { get; set; }
}

public class RangeQuestion : Question
{
    public object MinCorrectValue { get; set; }
    public object MaxCorrectValue { get; set; }
}

public class MultipleChoiceQuestion : Question
{
    public int NumberOfChoicesAllowed { get; set; }
    public List<MultipleChoiceOption> Choices { get; set; }
}

public class MultipleChoiceOption
{
    public char Letter { get; set; }
    public bool Correct { get; set; }
    public object Value { get; set; }
}

public class EssayQuestion : Question
{
    public int MinAnswerLength { get; set; }
    public int MaxAnswerLength { get; set; }
}

public class Exam
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public DateTime Taken { get; set; }
    public decimal Score { get; set; }
    public List<Answer> Answers { get; set; }
}

public class Answer
{
    public string QuestionId { get; set; }
    public bool Correct { get; set; }
    public object Value { get; set; }
}
public abstract class Question
{
    public string Id { get; set; }
    public string QuestionText { get; set; }
}

public class ValueQuestion<T> : Question
{
    public T CorrectValue { get; set; }
}

public class RangeQuestion<T> : Question
{
    public T MinCorrectValue { get; set; }
    public T MaxCorrectValue { get; set; }
}

public class MultipleChoiceQuestion<T> : Question
{
    public int NumberOfChoicesAllowed { get; set; }
    public List<MultipleChoiceOption<T>> Choices { get; set; }
}

public class MultipleChoiceOption<T>
{
    public char Letter { get; set; }
    public bool Correct { get; set; }
    public T Value { get; set; }
}

public class EssayQuestion : Question
{
    public int MinAnswerLength { get; set; }
    public int MaxAnswerLength { get; set; }
}

public class Exam
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public DateTime Taken { get; set; }
    public decimal Score { get; set; }
    public List<IAnswer> Answers { get; set; }
}

public interface IAnswer
{
    string QuestionId { get; set; }
    bool Correct { get; set; }
}

public class Answer<T> : IAnswer
{
    public string QuestionId { get; set; }
    public bool Correct { get; set; }
    public T Value { get; set; }
}