如何在C#基类数组中访问子类独有的属性?
解决方案:用多态+设计模式替代类型转换
1. 基类抽象方法:让子类实现自身逻辑
在Question基类中定义抽象方法,子类根据自身特性实现对应逻辑——这样遍历基类数组时,直接调用方法即可自动适配子类,完全不需要is/as类型转换。
比如针对属性访问和持久化需求,代码示例如下:
public abstract class Question { // 通用属性 public int Id { get; set; } public string Title { get; set; } // 抽象方法:子类实现自身的持久化逻辑 public abstract void SaveToDatabase(); // 抽象方法:返回子类特有属性的信息 public abstract string GetSpecificDetails(); } public class ChoiceQuestion : Question { // 子类独有属性 public List<string> Options { get; set; } public int CorrectOptionIndex { get; set; } public override void SaveToDatabase() { // 直接写入选择题数据表的逻辑,可直接使用Options、CorrectOptionIndex } public override string GetSpecificDetails() { return $"选项列表:{string.Join(", ", Options)},正确选项索引:{CorrectOptionIndex}"; } } public class FreeTextQuestion : Question { // 子类独有属性 public int MaxInputLength { get; set; } public override void SaveToDatabase() { // 直接写入开放题数据表的逻辑,可直接使用MaxInputLength } public override string GetSpecificDetails() { return $"最大输入长度限制:{MaxInputLength}"; } }
使用时无需任何类型判断:
Question[] questions = { new ChoiceQuestion(), new FreeTextQuestion() }; foreach (var question in questions) { question.SaveToDatabase(); // 自动调用对应子类的持久化逻辑 Console.WriteLine(question.GetSpecificDetails()); // 直接获取子类特有信息 }
2. 访问者模式:解耦复杂的多类型逻辑
如果持久化逻辑比较复杂(比如数据库操作不想和实体类耦合),或者需要外部类集中处理不同子类的逻辑,访问者模式是更合适的选择:
首先定义访问者接口:
public interface IQuestionVisitor { void VisitChoiceQuestion(ChoiceQuestion question); void VisitFreeTextQuestion(FreeTextQuestion question); }
在基类中添加接受访问的方法:
public abstract class Question { public int Id { get; set; } public string Title { get; set; } public abstract void Accept(IQuestionVisitor visitor); } public class ChoiceQuestion : Question { public List<string> Options { get; set; } public int CorrectOptionIndex { get; set; } public override void Accept(IQuestionVisitor visitor) { visitor.VisitChoiceQuestion(this); } } public class FreeTextQuestion : Question { public int MaxInputLength { get; set; } public override void Accept(IQuestionVisitor visitor) { visitor.VisitFreeTextQuestion(this); } }
然后实现数据库访问的访问者类:
public class QuestionDbSaver : IQuestionVisitor { public void VisitChoiceQuestion(ChoiceQuestion question) { // 处理选择题的数据库写入逻辑,直接访问子类特有属性 } public void VisitFreeTextQuestion(FreeTextQuestion question) { // 处理开放题的数据库写入逻辑,直接访问子类特有属性 } }
使用时只需传入访问者实例:
var dbSaver = new QuestionDbSaver(); Question[] questions = { new ChoiceQuestion(), new FreeTextQuestion() }; foreach (var question in questions) { question.Accept(dbSaver); // 自动匹配对应子类的保存逻辑 }
核心思路总结
- 多态的本质是基类定义契约,子类实现细节,调用者无需关心具体类型
- 把和类型强相关的逻辑(比如持久化、特有属性处理)放到子类或专门的访问者类中,避免在遍历逻辑里做类型判断
- 新增
Question子类时,只需实现基类抽象方法或访问者接口,无需修改原有遍历逻辑,符合开闭原则
内容的提问来源于stack exchange,提问作者Kilian Reichart
相关产品推荐
相关产品推荐

