Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何强制子类具有超类属性的特定子类?_C#_Entity Framework_Inheritance_Architecture_Abstract Class - Fatal编程技术网

C# 如何强制子类具有超类属性的特定子类?

C# 如何强制子类具有超类属性的特定子类?,c#,entity-framework,inheritance,architecture,abstract-class,C#,Entity Framework,Inheritance,Architecture,Abstract Class,首先,我与EF合作,因为我正在C#上构建一个MVC应用程序。我希望不同类型的考试有不同类型的问题。以下是我的抽象类: public abstract class Exam { public int Id { get; set; } public string Description { set; get; } public abstract ICollection<Question> GetQuestions(); public abstract v

首先,我与EF合作,因为我正在C#上构建一个MVC应用程序。我希望不同类型的考试有不同类型的问题。以下是我的抽象类:

public abstract class Exam
{
    public int Id { get; set; }
    public string Description { set; get; }

    public abstract ICollection<Question> GetQuestions();
    public abstract void SetQuestions(ICollection<Question> questions);
}

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

    public abstract Exam getExam();
    public abstract void setExam(Exam exam);
}
我之所以这么做,是因为一个多重测验应该只有多重测验,一个单一的考试应该只有单一的问题,就像多重测验应该有多重测验,单一的问题应该有单一的考试一样


有没有更好的方法来确保类“a”的子类包含或具有类“B”的特定子类(就像我的考试和问题一样),并且可以通过抽象类访问它,而不需要抽象的getter和setter?

正如其他人提到的,我认为您的问题过于复杂了。 然而;你的问题是关于类型保证的,我会尽力回答

首先是守则:

public interface IExam<out T> where T:IQuestion {
  int Id { get; set; }
  string Description { set; get; }
  IEnumerable<T> GetQuestions();
}

public interface IQuestion{
  int Id { get; set; }
  string Description { set; get; }
  IExam<IQuestion> Exam { get; }
}

public class SingleQuestion:IQuestion {
  public string Description { get; set; }
  public int Id { get; set; }
  IExam<IQuestion> IQuestion.Exam {
    get { return Exam; }
  }
  public SingleExam Exam { get; set; }
}

public class SingleExam:IExam<SingleQuestion> {
  public int Id { get; set; }
  public string Description { get; set; }

  private IEnumerable<SingleQuestion> _questions;
  public IEnumerable<SingleQuestion> GetQuestions() {
    return _questions;
  }

  public void SetQuestions(IEnumerable<SingleQuestion> questions) {
    _questions = questions;
  }
}
公共接口IExam,其中T:IQuestion{
int Id{get;set;}
字符串说明{set;get;}
IEnumerable GetQuestions();
}
公共接口测试{
int Id{get;set;}
字符串说明{set;get;}
IExam考试{get;}
}
公共类问题:IQuestion{
公共字符串说明{get;set;}
公共int Id{get;set;}
伊克萨姆考试{
获取{return Exam;}
}
公共单一考试{get;set;}
}
公开课单项考试:IExam{
公共int Id{get;set;}
公共字符串说明{get;set;}
私人问题;
公共IEnumerable GetQuestions(){
返回问题;
}
公共问题(IEnumerable问题){
_问题=问题;
}
}
首先,我们用接口替换了抽象类。 这是必需的,因为我们希望使IExam在IQuestion上协变,并且协变只能在接口中定义。这也是我们将集合更改为IEnumerable的原因

注意:我们没有在IExam中定义SetQuestions方法,简而言之,这是因为我们不能。从长远来看,这是因为,这将使T变为反变项以及反变项,从而导致无法进行型式保证的情况

IQuestions相当直截了当,这里没有真正的变化。我想,你可以把它作为一个抽象类型

现在,实现: 在SingleQuestion中,我们必须显式实现需要IExam的检查,然后使用返回SingleExam的属性对其进行阴影处理。 这使我们能够返回尽可能精确的检查类型

SingleQuestion sq = new SingleQuestion();
IQuestion q = sq; //Upcast
sq.Exam; //returns a SingleExam
q.Exam; //returns a IExam<IQuestion>
SingleQuestion sq=新的SingleQuestion();
q=sq//上抛
sq.考试//返回单个测试
q、 考试//返回一个IExam
在单题考试中,您现在可以设置问题并对其进行限制,以便只添加单题

另一方面,现在更容易理解为什么设置问题不能在IExam中定义。考虑以下事项:

SingleExam se = new SingleExam();
IExam<IQuestion> singleUpcast = se;
//What type of question can we set on singleUpcast?
SingleExam se=newsingleexam();
IExam singleUpcast=se;
//我们可以在单播上设置什么类型的问题?

我们所知道的是singleUpcast包含IQuestions,但我们不能只添加IQuestions,因为singleUpcast最终是SingleExam的一个实例,它承诺只能设置SingleQuestions。简而言之,在不破坏类型保证的情况下,不可能知道哪些类型可以添加到IExam中

为什么一个问题需要知道它正在进行的考试?它们只是导航属性,但并不十分重要(尽管正确映射数据库需要ExamId)。真正重要的是确保不同类型的考试包含特定的问题子类。如果你没有遗漏关于单独(多个/单个)考试和(多个/单个)问题类型目的的其他细节,这种方法似乎过于复杂。单一的考试和问题课不是更容易吗?如果您需要添加单个和多个考试之间的区别,您可以添加在构造函数中设置的bool Single属性,并控制考试是否只能有一个或多个问题。功能将非常不同。我忽略了细节,但是单问题和多问题将有不同的领域和功能,也许考虑到@Richard所说的是有意义的。您可以有两个新的实体
ExamType
QuestionType
,通过建立它们之间的关系,您可以管理哪些考试类型可能有哪些问题类型。你的
考试
有一个
考试类型
,你的
问题
有一个
问题类型
。此外,您可以有一个“基本”考试类,并且“特殊许可”考试可以从中继承(使用TPH、TPT或TPC进行数据库映射)
SingleQuestion sq = new SingleQuestion();
IQuestion q = sq; //Upcast
sq.Exam; //returns a SingleExam
q.Exam; //returns a IExam<IQuestion>
SingleExam se = new SingleExam();
IExam<IQuestion> singleUpcast = se;
//What type of question can we set on singleUpcast?