You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:48:18